From 304255eb3bd2e7df8137401ba107859f181b7c6b Mon Sep 17 00:00:00 2001 From: Jhobean <51728381+Jhobean@users.noreply.github.com> Date: Wed, 25 Sep 2024 04:15:13 -0400 Subject: [PATCH 01/32] Update sphereCrypt.ini (#1297) --- src/sphereCrypt.ini | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/sphereCrypt.ini b/src/sphereCrypt.ini index ad5e2d934..ad0616d0b 100644 --- a/src/sphereCrypt.ini +++ b/src/sphereCrypt.ini @@ -25,6 +25,8 @@ ENC_LOGIN 4 // Rotation cipher used for the Login Server crypt by every client, [SPHERECRYPT] //Classic Clients +7010400 03907237D 0A84B527F ENC_TFISH // 7.0.104.00 +7010300 03949418D 0A864FE7F ENC_TFISH // 7.0.103.00 70010200 03992EB9D 0A81E227F ENC_TFISH // 7.0.102 70010100 039C411AD 0A803DE7F ENC_TFISH // 7.0.101 70010000 03A3D83BD 0A9F5127F ENC_TFISH // 7.0.100 @@ -227,6 +229,8 @@ ENC_LOGIN 4 // Rotation cipher used for the Login Server crypt by every client, 1232700 0D47BD45C 034081CD6 ENC_LOGIN // 1.23.27 //Enhanced Clients +6790010400 01B07237D 0B94B527F ENC_TFISH // 4.00.104 +6790010300 01B49418D 0B964FE7F ENC_TFISH // 4.00.103 670010200 01B92EB9D 0B91E227F ENC_TFISH // 4.00.102 670010100 01BC411AD 0B903DE7F ENC_TFISH // 4.00.101 670010000 0183D83BD 0B8F5127F ENC_TFISH // 4.00.100 From 30281385d4f1bee5610abdc1398a7a30f254e513 Mon Sep 17 00:00:00 2001 From: Jhobean Date: Sat, 5 Oct 2024 10:50:24 -0400 Subject: [PATCH 02/32] Add @petrelease trigger --- Changelog.txt | 3 +++ src/game/CObjBase.h | 1 + src/game/chars/CChar.cpp | 1 + src/game/chars/CCharNPCPet.cpp | 10 ++++++++++ src/tables/triggers.tbl | 1 + 5 files changed, 16 insertions(+) diff --git a/Changelog.txt b/Changelog.txt index 210e47371..3e94dedc4 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -3902,3 +3902,6 @@ Added: 'H' shortcut for variables to get the value as hexadecimal. - Changed: added desired FollowerSlots as a second argument to CURFOLLOWER.ADD. Default value: its FollowerSlots. - Changed: @FollowerUpdate ARGN1 and ARGN2 are now read-only. Having them RW and actually get them working would have meant many other changes, breaking script compatibility. - Fixed: CURFOLLOWER.DEL/DELETE/CLEAR not working properly. + +05-10-2024, Jhobean +- Added: @PetRelease trigger work like @petdesert and return 1 to prevent the pet from being released. diff --git a/src/game/CObjBase.h b/src/game/CObjBase.h index 7a94ef5e1..e34a42979 100644 --- a/src/game/CObjBase.h +++ b/src/game/CObjBase.h @@ -1170,6 +1170,7 @@ enum CTRIG_TYPE : short CTRIG_PayGold, // I'm going to give out money for a service (Skill Training, hiring...). CTRIG_PersonalSpace, // i just got stepped on by other char. CTRIG_PetDesert, // I'm deserting from my owner ( starving, being hit by him ...). + CTRIG_PetRelease, // I have been released by my owner. CTRIG_Profile, // someone hit the profile button for me. CTRIG_ReceiveItem, // I was just handed an item (Not yet checked if i want it). CTRIG_RegenStat, // Hits/mana/stam/food regeneration. diff --git a/src/game/chars/CChar.cpp b/src/game/chars/CChar.cpp index cf14716cc..5c90e79a1 100644 --- a/src/game/chars/CChar.cpp +++ b/src/game/chars/CChar.cpp @@ -169,6 +169,7 @@ lpctstr const CChar::sm_szTrigName[CTRIG_QTY+1] = // static "@PayGold", // I'm going to give out money for a service (Skill Training, hiring...). "@PersonalSpace", // +i just got stepped on by other char. "@PetDesert", // I just went wild again + "@PetRelease", // I just been released by my master "@Profile", // someone hit the profile button for me. "@ReceiveItem", // I was just handed an item (Not yet checked if i want it) "@RegenStat", // Regenerating any stat diff --git a/src/game/chars/CCharNPCPet.cpp b/src/game/chars/CCharNPCPet.cpp index a9ce07c0a..91e65ff6a 100644 --- a/src/game/chars/CCharNPCPet.cpp +++ b/src/game/chars/CCharNPCPet.cpp @@ -857,6 +857,16 @@ void CChar::NPC_PetRelease() if (!m_pNPC) return; + CChar* pCharOwn = NPC_PetGetOwner(); + if (!pCharOwn) + return; + + if (IsTrigUsed(TRIGGER_PETRELEASE)) + { + if (OnTrigger(CTRIG_PetRelease, pCharOwn, nullptr) == TRIGRET_RET_TRUE) + return; + } + if (IsStatFlag(STATF_CONJURED) || (m_pNPC->m_bonded && IsStatFlag(STATF_DEAD))) { Effect(EFFECT_XYZ, ITEMID_FX_TELE_VANISH, this, 10, 15); diff --git a/src/tables/triggers.tbl b/src/tables/triggers.tbl index b81dc78ff..a200f613a 100644 --- a/src/tables/triggers.tbl +++ b/src/tables/triggers.tbl @@ -156,6 +156,7 @@ ADD(PARTYREMOVE) ADD(PAYGOLD) ADD(PERSONALSPACE) ADD(PETDESERT) +ADD(PETRELEASE) ADD(PICKUP_GROUND) ADD(PICKUP_PACK) ADD(PICKUP_SELF) From 6baa1634affe3974fe33d2f2f7f47e25cc0251f7 Mon Sep 17 00:00:00 2001 From: Jhobean Date: Wed, 9 Oct 2024 22:31:57 -0400 Subject: [PATCH 03/32] Add @DisplayName to be able control the name other player see. --- src/game/CObjBase.h | 1 + src/game/chars/CChar.cpp | 1 + src/network/send.cpp | 50 ++++++++++++++++++++++++++++++++++++---- src/network/send.h | 2 +- src/tables/triggers.tbl | 1 + 5 files changed, 50 insertions(+), 5 deletions(-) diff --git a/src/game/CObjBase.h b/src/game/CObjBase.h index 7a94ef5e1..efaf2930d 100644 --- a/src/game/CObjBase.h +++ b/src/game/CObjBase.h @@ -1072,6 +1072,7 @@ enum CTRIG_TYPE : short CTRIG_DelMulti, // Delete the given multi to the CMultiStorage of this char (player). CTRIG_Destroy, // I am nearly destroyed. CTRIG_Dismount, // I'm dismounting. + CTRIG_DisplayName, // Paperdoll and status is sent and I can change the display name CTRIG_Drink, // I'm drinking something. CTRIG_DYE, CTRIG_Eat, // I'm eating something. diff --git a/src/game/chars/CChar.cpp b/src/game/chars/CChar.cpp index cf14716cc..f8ec388d6 100644 --- a/src/game/chars/CChar.cpp +++ b/src/game/chars/CChar.cpp @@ -71,6 +71,7 @@ lpctstr const CChar::sm_szTrigName[CTRIG_QTY+1] = // static "@DelMulti", // Removing a multi to the MultiStorage, "@Destroy", //+I am nearly destroyed "@Dismount", // I am trying to get rid of my ride right now + "@DisplayName", // Name Show on the paperdoll and status bar "@Drink", // I am drinking something. "@Dye", // My color has been changed "@Eat", diff --git a/src/network/send.cpp b/src/network/send.cpp index b70bc8527..8d88bc10d 100644 --- a/src/network/send.cpp +++ b/src/network/send.cpp @@ -18,6 +18,7 @@ #include "../game/uo_files/uofiles_enums_creid.h" #include "../game/CServer.h" #include "../game/CWorldGameTime.h" +#include "../game/triggers.h" #include "CNetworkManager.h" #include "send.h" @@ -25,6 +26,8 @@ namespace zlib { #include } #include +#include "../game/components/CCChampion.h" +#include "../common/resource/sections/CRegionResourceDef.h" /*************************************************************************** @@ -142,7 +145,26 @@ PacketObjectStatus::PacketObjectStatus(const CClient* target, CObjBase* object) initLength(); writeInt32(object->GetUID()); - writeStringFixedASCII(object->GetName(), 30); + + bool bCustomName=0; + lpctstr ShowName; + if (objectChar != nullptr && + objectChar->IsClientType() && + IsTrigUsed(TRIGGER_DISPLAYNAME) && + (objectChar != character)) //Avoid launch trigger if the target is the same character + { + CScriptTriggerArgs args; + args.m_s1 = object->GetName(); + + CChar* pCharBase = const_cast(character); // Remove the const to be able to use on OnTrigger + if (objectChar->OnTrigger(CTRIG_DisplayName, pCharBase, &args) == TRIGRET_RET_TRUE) + { + bCustomName = 1; + ShowName = args.m_s1; + } + } + + writeStringFixedASCII(bCustomName ? ShowName : object->GetName(), 30); if (state->isClientVersionNumber(MINCLIVER_STATUS_V6)) version = 6; @@ -2604,7 +2626,7 @@ PacketCharacterListUpdate::PacketCharacterListUpdate(CClient* target, const CCha * * ***************************************************************************/ -PacketPaperdoll::PacketPaperdoll(const CClient* target, const CChar* character) : PacketSend(XCMD_PaperDoll, 66, g_Cfg.m_fUsePacketPriorities? PRI_LOW : PRI_NORMAL) +PacketPaperdoll::PacketPaperdoll(const CClient* target, CChar* character) : PacketSend(XCMD_PaperDoll, 66, g_Cfg.m_fUsePacketPriorities? PRI_LOW : PRI_NORMAL) { ADDTOCALLSTACK("PacketPaperdoll::PacketPaperdoll"); @@ -2619,15 +2641,34 @@ PacketPaperdoll::PacketPaperdoll(const CClient* target, const CChar* character) writeInt32(character->GetUID()); + bool bCustomName = 0; + CSString ShowName; + + + if (IsTrigUsed(TRIGGER_DISPLAYNAME) && (target->GetChar() != character)) //Avoid launch trigger if the target is the same character + { + CScriptTriggerArgs args; + args.m_s1 = character->GetName(); + if (character->OnTrigger(CTRIG_DisplayName, target->GetChar(), &args) == TRIGRET_RET_TRUE) + { + bCustomName = 1; + ShowName = args.m_s1; + } + } + if (character->IsStatFlag(STATF_INCOGNITO)) { writeStringFixedASCII(character->GetName(), 60); - } + } + else if (bCustomName) + { + writeStringFixedASCII(ShowName, 60); + } else { tchar* text = Str_GetTemp(); - int len = 0; + int len = 0; const CStoneMember* guildMember = character->Guild_FindMember(MEMORY_GUILD); if (guildMember != nullptr && guildMember->IsAbbrevOn() && guildMember->GetParentStone()->GetAbbrev()[0]) { @@ -2651,6 +2692,7 @@ PacketPaperdoll::PacketPaperdoll(const CClient* target, const CChar* character) } writeByte((byte)mode); + push(target); } diff --git a/src/network/send.h b/src/network/send.h index 52f5d41a2..7b9d59617 100644 --- a/src/network/send.h +++ b/src/network/send.h @@ -948,7 +948,7 @@ class PacketCharacterListUpdate : public PacketSend class PacketPaperdoll : public PacketSend { public: - PacketPaperdoll(const CClient* target, const CChar* character); + PacketPaperdoll(const CClient* target, CChar* character); }; /*************************************************************************** diff --git a/src/tables/triggers.tbl b/src/tables/triggers.tbl index b81dc78ff..274eb1d4f 100644 --- a/src/tables/triggers.tbl +++ b/src/tables/triggers.tbl @@ -49,6 +49,7 @@ ADD(DELREDCANDLE) ADD(DELWHITECANDLE) ADD(DESTROY) ADD(DISMOUNT) +ADD(DISPLAYNAME) ADD(DRINK) ADD(DROPON_CHAR) ADD(DROPON_GROUND) From 4183b8459d244ff5682d66ca5fc7a8bf291cb789 Mon Sep 17 00:00:00 2001 From: Jhobean <51728381+Jhobean@users.noreply.github.com> Date: Fri, 11 Oct 2024 15:19:58 -0400 Subject: [PATCH 04/32] Add changelog and fix string bug --- Changelog.txt | 7 +++++++ src/network/send.cpp | 18 +++++++++--------- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/Changelog.txt b/Changelog.txt index 210e47371..f7b671a30 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -3902,3 +3902,10 @@ Added: 'H' shortcut for variables to get the value as hexadecimal. - Changed: added desired FollowerSlots as a second argument to CURFOLLOWER.ADD. Default value: its FollowerSlots. - Changed: @FollowerUpdate ARGN1 and ARGN2 are now read-only. Having them RW and actually get them working would have meant many other changes, breaking script compatibility. - Fixed: CURFOLLOWER.DEL/DELETE/CLEAR not working properly. + +11-10-2024, Jhobean +- Added: @DisplayName give possibility to change the name other player see on the paperdoll and on status bar. Could be use on RP server where unknow person don't know your name before presentation. + src.: The player requesting to view the name on the paperdoll or status + i: The player stalked by the src. + ARGS (R/W): The name to display + RETURN 1 : Change the name to the new value of ARGS diff --git a/src/network/send.cpp b/src/network/send.cpp index 8d88bc10d..3d7b3080b 100644 --- a/src/network/send.cpp +++ b/src/network/send.cpp @@ -26,8 +26,6 @@ namespace zlib { #include } #include -#include "../game/components/CCChampion.h" -#include "../common/resource/sections/CRegionResourceDef.h" /*************************************************************************** @@ -147,7 +145,7 @@ PacketObjectStatus::PacketObjectStatus(const CClient* target, CObjBase* object) writeInt32(object->GetUID()); bool bCustomName=0; - lpctstr ShowName; + CSString sShowName; if (objectChar != nullptr && objectChar->IsClientType() && IsTrigUsed(TRIGGER_DISPLAYNAME) && @@ -160,11 +158,13 @@ PacketObjectStatus::PacketObjectStatus(const CClient* target, CObjBase* object) if (objectChar->OnTrigger(CTRIG_DisplayName, pCharBase, &args) == TRIGRET_RET_TRUE) { bCustomName = 1; - ShowName = args.m_s1; + sShowName = args.m_s1; } } - - writeStringFixedASCII(bCustomName ? ShowName : object->GetName(), 30); + if (bCustomName) + writeStringFixedASCII(sShowName, 30); + else + writeStringFixedASCII(object->GetName(), 30); if (state->isClientVersionNumber(MINCLIVER_STATUS_V6)) version = 6; @@ -2642,7 +2642,7 @@ PacketPaperdoll::PacketPaperdoll(const CClient* target, CChar* character) : Pack writeInt32(character->GetUID()); bool bCustomName = 0; - CSString ShowName; + CSString sShowName; if (IsTrigUsed(TRIGGER_DISPLAYNAME) && (target->GetChar() != character)) //Avoid launch trigger if the target is the same character @@ -2652,7 +2652,7 @@ PacketPaperdoll::PacketPaperdoll(const CClient* target, CChar* character) : Pack if (character->OnTrigger(CTRIG_DisplayName, target->GetChar(), &args) == TRIGRET_RET_TRUE) { bCustomName = 1; - ShowName = args.m_s1; + sShowName = args.m_s1; } } @@ -2662,7 +2662,7 @@ PacketPaperdoll::PacketPaperdoll(const CClient* target, CChar* character) : Pack } else if (bCustomName) { - writeStringFixedASCII(ShowName, 60); + writeStringFixedASCII(sShowName, 60); } else { From 56d5f1fe937520a765cda1647fdabbe1b108d3eb Mon Sep 17 00:00:00 2001 From: Jhobean <51728381+Jhobean@users.noreply.github.com> Date: Fri, 11 Oct 2024 15:28:39 -0400 Subject: [PATCH 05/32] Change the const_cast by removing const --- src/network/send.cpp | 7 +++---- src/network/send.h | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/network/send.cpp b/src/network/send.cpp index 3d7b3080b..5b8880984 100644 --- a/src/network/send.cpp +++ b/src/network/send.cpp @@ -128,13 +128,13 @@ PacketCombatDamage::PacketCombatDamage(const CClient* target, word damage, CUID * * ***************************************************************************/ -PacketObjectStatus::PacketObjectStatus(const CClient* target, CObjBase* object) : PacketSend(XCMD_Status, 7, g_Cfg.m_fUsePacketPriorities? PRI_LOW : PRI_NORMAL) +PacketObjectStatus::PacketObjectStatus(CClient* target, CObjBase* object) : PacketSend(XCMD_Status, 7, g_Cfg.m_fUsePacketPriorities? PRI_LOW : PRI_NORMAL) { ADDTOCALLSTACK("PacketObjectStatus::PacketObjectStatus"); ASSERT(object); const CNetState * state = target->GetNetState(); - const CChar *character = target->GetChar(); + CChar *character = target->GetChar(); CChar *objectChar = object->IsChar() ? static_cast(object) : nullptr; bool fCanRename = false; @@ -154,8 +154,7 @@ PacketObjectStatus::PacketObjectStatus(const CClient* target, CObjBase* object) CScriptTriggerArgs args; args.m_s1 = object->GetName(); - CChar* pCharBase = const_cast(character); // Remove the const to be able to use on OnTrigger - if (objectChar->OnTrigger(CTRIG_DisplayName, pCharBase, &args) == TRIGRET_RET_TRUE) + if (objectChar->OnTrigger(CTRIG_DisplayName, character, &args) == TRIGRET_RET_TRUE) { bCustomName = 1; sShowName = args.m_s1; diff --git a/src/network/send.h b/src/network/send.h index 7b9d59617..b0f732131 100644 --- a/src/network/send.h +++ b/src/network/send.h @@ -111,7 +111,7 @@ class PacketCombatDamage : public PacketSend class PacketObjectStatus : public PacketSend { public: - PacketObjectStatus(const CClient* target, CObjBase* object); + PacketObjectStatus(CClient* target, CObjBase* object); private: void WriteVersionSpecific(const CClient* target, CChar* other, byte version); From 575d5391d4b53b11e261934cb82762b5bc7a1c39 Mon Sep 17 00:00:00 2001 From: cbnolok Date: Sat, 21 Sep 2024 13:53:26 +0200 Subject: [PATCH 06/32] Added sanitizers options to CompilerFlagsChecker.cmake --- CMakeLists.txt | 14 +- cmake/CompilerFlagsChecker.cmake | 218 +++++++++++++++++++++++-------- 2 files changed, 164 insertions(+), 68 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9c7bb54b6..29766560a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,7 +3,6 @@ cmake_minimum_required(VERSION 3.24) set(CMAKE_SUPPRESS_REGENERATION TRUE) # Supress the ZERO_CHECK generation - # -------------------- GUI checkboxes -------------------- option( CMAKE_NO_GIT_REVISION @@ -30,10 +29,11 @@ if(WIN32) option(WIN32_SPAWN_CONSOLE "Spawn an additional console, useful for debugging." FALSE) endif() +option(USE_COMPILER_HARDENING_OPTIONS "Enable compiler (even runtime) safety checks and code hardening." FALSE) option(USE_ASAN "Enable AddressSanitizer." FALSE) -option(USE_MSAN "Enable MemorySanitizer." FALSE) -option(USE_LSAN "Enable LeakSanitizer." FALSE) option(USE_UBSAN "Enable Undefined Behavior Sanitizer." FALSE) +option(USE_LSAN "Enable LeakSanitizer." FALSE) +option(USE_MSAN "Enable MemorySanitizer." FALSE) # -------------------- Utility functions -------------------- function(booleanize_str_find VAR) @@ -44,7 +44,6 @@ function(booleanize_str_find VAR) endif() endfunction() - # -------------------- Start: initializations -------------------- # Should i load the toolchain passed as argument? @@ -102,7 +101,6 @@ if(NOT TOOLCHAIN_LOADED) include("cmake/DetectDefaultToolchain.cmake") endif() - # -------------------- Stuff that needs to be executed after PROJECT but before ADD_EXECUTABLE message(STATUS) @@ -126,7 +124,7 @@ if(SINGLE_TARGET) set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Nightly" "Release") if(NOT ${CMAKE_BUILD_TYPE} STREQUAL "") if( - ( NOT ${CMAKE_BUILD_TYPE} STREQUAL "Release") + (NOT ${CMAKE_BUILD_TYPE} STREQUAL "Release") AND (NOT ${CMAKE_BUILD_TYPE} STREQUAL "Debug") AND (NOT ${CMAKE_BUILD_TYPE} STREQUAL "Nightly") ) @@ -157,11 +155,9 @@ else(SINGLE_TARGET) set(CMAKE_CONFIGURATION_TYPES "Debug;Release;Nightly" CACHE STRING "" FORCE) endif(SINGLE_TARGET) - # Include the list of all Sphere source files include("src/CMakeSources.cmake") - # Configure output binaries set(TARGETS "" CACHE INTERNAL "List of Sphere targets to build.") if(SINGLE_TARGET) @@ -215,7 +211,6 @@ else(SINGLE_TARGET) target_precompile_headers(spheresvr ${pch_options}) endif(SINGLE_TARGET) - # -------------------- #message(STATUS) @@ -229,7 +224,6 @@ message(STATUS) message(STATUS "Configuring external libraries...") add_subdirectory(lib) - message(STATUS) toolchain_exe_stuff() # stuff to be executed after ADD_EXECUTABLE diff --git a/cmake/CompilerFlagsChecker.cmake b/cmake/CompilerFlagsChecker.cmake index 0e2e0399e..6826f0cac 100644 --- a/cmake/CompilerFlagsChecker.cmake +++ b/cmake/CompilerFlagsChecker.cmake @@ -1,8 +1,7 @@ include(CheckCXXCompilerFlag) message(STATUS "Checking available compiler flags...") - -if (NOT MSVC) +if(NOT MSVC) message(STATUS "-- Compilation options:") # Compiler option flags. Common to both compilers, but older versions might not support the following. #check_cxx_compiler_flag("" COMP_HAS_) @@ -13,29 +12,79 @@ if (NOT MSVC) # Compiler option flags. Expected to work on Clang but not GCC, at the moment. #check_cxx_compiler_flag("-fforce-emit-vtables" COMP_HAS_F_FORCE_EMIT_VTABLES) - message(STATUS "-- Compilation options (Address Sanitizer):") - # Compiler option flags. Sanitizers related (ASAN). - #check_cxx_compiler_flag("-fsanitize=safe-stack" COMP_HAS_) # Can't be used with asan! - check_cxx_compiler_flag("-fsanitize-cfi" COMP_HAS_FSAN_CFI) # cfi: control flow integrity - check_cxx_compiler_flag("-fsanitize-address-use-after-scope" COMP_HAS_FSAN_ADDRESS_USE_AFTER_SCOPE) - check_cxx_compiler_flag("-fsanitize=pointer-compare" COMP_HAS_FSAN_PTR_COMP) - check_cxx_compiler_flag("-fsanitize=pointer-subtract" COMP_HAS_FSAN_PTR_SUB) - check_cxx_compiler_flag("-fsanitize-trap=all" COMP_HAS_FSAN_TRAP_ALL) - - message(STATUS "-- Compilation options (Sanitizers-related and safety checks):") - # Compiler option flags. Sanitizers related (other). - # fsanitize=signed-integer-overflow # -fno-strict-overflow (which implies -fwrapv-pointer and -fwrapv) - check_cxx_compiler_flag("-fcf-protection=full" COMP_HAS_FCF_PROTECTION_FULL) - check_cxx_compiler_flag("-fstack-check" COMP_HAS_F_STACK_CHECK) - check_cxx_compiler_flag("-fstack-protector-all" COMP_HAS_F_STACK_PROTECTOR_ALL) - check_cxx_compiler_flag("-fstack-protector-strong" COMP_HAS_F_STACK_PROTECTOR_STRONG) - check_cxx_compiler_flag("-fstack-protector" COMP_HAS_F_STACK_PROTECTOR) - check_cxx_compiler_flag("-fstack-clash-protection" COMP_HAS_F_STACK_CLASH_PROTECTION) - #Flags GCC specific? - check_cxx_compiler_flag("-fvtable-verify=preinit" COMP_HAS_F_VTABLE_VERIFY_PREINIT) - check_cxx_compiler_flag("-fharden-control-flow-redundancy" COMP_HAS_F_HARDEN_CFR) - check_cxx_compiler_flag("-fhardcfr-check-exceptions" COMP_HAS_F_HARDCFR_CHECK_EXCEPTIONS) - #check_cxx_compiler_flag("" COMP_HAS_) + if(${USE_ASAN}) + # Compiler option flags. Sanitizers related (ASAN). + message(STATUS "-- Compilation options (Address Sanitizer):") + + check_cxx_compiler_flag("-fsanitize=address" COMP_HAS_ASAN) + if(NOT COMP_HAS_ASAN) + message(FATAL_ERROR "This compiler does not support Address Sanitizer. Disable it.") + endif() + + check_cxx_compiler_flag("-fsanitize-cfi" COMP_HAS_FSAN_CFI) # cfi: control flow integrity + check_cxx_compiler_flag("-fsanitize-address-use-after-scope" COMP_HAS_FSAN_ADDRESS_USE_AFTER_SCOPE) + check_cxx_compiler_flag("-fsanitize=pointer-compare" COMP_HAS_FSAN_PTR_COMP) + check_cxx_compiler_flag("-fsanitize=pointer-subtract" COMP_HAS_FSAN_PTR_SUB) + check_cxx_compiler_flag("-fsanitize-trap=all" COMP_HAS_FSAN_TRAP_ALL) + endif() + + if(${USE_UBSAN}) + # Compiler option flags. Sanitizers related (UBSAN). + message(STATUS "-- Compilation options (Undefined Behavior Sanitizer):") + + check_cxx_compiler_flag("-fsanitize=undefined" COMP_HAS_UBSAN) + if(NOT COMP_HAS_UBSAN) + message(FATAL_ERROR "This compiler does not support Undefined Behavior Sanitizer. Disable it.") + endif() + + check_cxx_compiler_flag("-fsanitize=float-divide-by-zero" COMP_HAS_FSAN_FLOAT_DIVIDE_BY_ZERO) + check_cxx_compiler_flag("-fsanitize=unsigned-integer-overflow" COMP_HAS_FSAN_UNSIGNED_INTEGER_OVERFLOW) #Unlike signed integer overflow, this is not undefined behavior, but it is often unintentional. + #check_cxx_compiler_flag("-fsanitize=implicit-conversion" COMP_HAS_FSAN_IMPLICIT_CONVERSION) + #check_cxx_compiler_flag("-fsanitize=local-bounds" COMP_HAS_FSAN_LOCAL_BOUNDS) + check_cxx_compiler_flag("-fno-sanitize=enum" COMP_HAS_FSAN_NO_ENUM) + endif() + + if(${USE_LSAN}) + # Compiler option flags. Sanitizers related (LSAN). + message(STATUS "-- Compilation options (Leak Sanitizer):") + + check_cxx_compiler_flag("-fsanitize=leak" COMP_HAS_LSAN) + if(NOT COMP_HAS_LSAN) + message(FATAL_ERROR "This compiler does not support Leak Sanitizer. Disable it.") + endif() + endif() + + if(${USE_MSAN}) + # Compiler option flags. Sanitizers related (UBSAN). + + message(STATUS "-- Compilation options (Memory Behavior Sanitizer):") + check_cxx_compiler_flag("-fsanitize=memory" COMP_HAS_MSAN) + if(NOT COMP_HAS_MSAN) + message(FATAL_ERROR "This compiler does not support Memory Sanitizer. Disable it.") + endif() + + check_cxx_compiler_flag("-fsanitize=memory-track-origins" COMP_HAS_F_SANITIZE_MEMORY_TRACK_ORIGINS) + check_cxx_compiler_flag("-fPIE" COMP_HAS_F_PIE) + endif() + + if(USE_COMPILER_HARDENING_OPTIONS) + message(STATUS "-- Compilation options (code hardening):") + # Compiler option flags. Other sanitizers or code hardening. + if(NOT USE_ASAN) + check_cxx_compiler_flag("-fsanitize=safe-stack" COMP_HAS_F_SANITIZE_SAFE_STACK) # Can't be used with asan! + endif() + check_cxx_compiler_flag("-fcf-protection=full" COMP_HAS_FCF_PROTECTION_FULL) + check_cxx_compiler_flag("-fstack-check" COMP_HAS_F_STACK_CHECK) + check_cxx_compiler_flag("-fstack-protector-all" COMP_HAS_F_STACK_PROTECTOR_ALL) + check_cxx_compiler_flag("-fstack-protector-strong" COMP_HAS_F_STACK_PROTECTOR_STRONG) + check_cxx_compiler_flag("-fstack-protector" COMP_HAS_F_STACK_PROTECTOR) + check_cxx_compiler_flag("-fstack-clash-protection" COMP_HAS_F_STACK_CLASH_PROTECTION) + #Flags GCC specific? + check_cxx_compiler_flag("-fvtable-verify=preinit" COMP_HAS_F_VTABLE_VERIFY_PREINIT) + check_cxx_compiler_flag("-fharden-control-flow-redundancy" COMP_HAS_F_HARDEN_CFR) + check_cxx_compiler_flag("-fhardcfr-check-exceptions" COMP_HAS_F_HARDCFR_CHECK_EXCEPTIONS) + #check_cxx_compiler_flag("" COMP_HAS_) + endif() # Compiler warning flags. message(STATUS "-- Compilation options (warnings):") @@ -65,7 +114,6 @@ if (NOT MSVC) #check_cxx_compiler_flag("" COMP_HAS_) # Compiler warning flags. TODO: To be evaluated... - # -Wshadow # -Wfree-nonheap-object (good but false positive warnings on GCC?) # -Wcast-align=strict # -Wcast-user-defined @@ -86,15 +134,13 @@ if (NOT MSVC) check_cxx_compiler_flag("-Wno-deprecated-declarations" COMP_HAS_WNO_DEPRECATED_DECLARATIONS) #check_cxx_compiler_flag("-Wno-unknown-pragmas" COMP_HAS_) #check_cxx_compiler_flag("" COMP_HAS_) - -else (NOT MSVC) +else(NOT MSVC) # Compiler warning flags (MSVC). message(STATUS "-- Compilation options (MSVC):") check_cxx_compiler_flag("/Wd5105" COMP_HAS_DEFINE_MACRO_EXPANSION) # False positive warning, maybe even a MSVC bug. #check_cxx_compiler_flag("" COMP_HAS_) endif() - # ---- Append options into some lists. # ---- GCC/Clang @@ -103,47 +149,85 @@ if(COMP_HAS_FNO_EXPENSIVE_OPTIMIZATIONS) list(APPEND checked_compiler_options "-fno-expensive-optimizations") endif() -if(COMP_HAS_FSAN_CFI) - list(APPEND checked_compiler_options_asan "-fsanitize-cfi") +if(COMP_HAS_ASAN) + list(APPEND checked_compiler_options_asan "-fsanitize=address") + if(COMP_HAS_FSAN_CFI) + list(APPEND checked_compiler_options_asan "-fsanitize-cfi") + endif() + if(COMP_HAS_FSAN_ADDRESS_USE_AFTER_SCOPE) + list(APPEND checked_compiler_options_asan "-fsanitize-address-use-after-scope") + endif() + if(COMP_HAS_FSAN_PTR_COMP) + list(APPEND checked_compiler_options_asan "-fsanitize=pointer-compare") + endif() + if(COMP_HAS_FSAN_PTR_SUB) + list(APPEND checked_compiler_options_asan "-fsanitize=pointer-subtract") + endif() + if(COMP_HAS_FSAN_TRAP_ALL) + list(APPEND checked_compiler_options_asan "-fsanitize-trap=all") + endif() endif() -if(COMP_HAS_FSAN_ADDRESS_USE_AFTER_SCOPE) - list(APPEND checked_compiler_options_asan "-fsanitize-address-use-after-scope") -endif() -if(COMP_HAS_FSAN_PTR_COMP) - list(APPEND checked_compiler_options_asan "-fsanitize=pointer-compare" ) + +if(COMP_HAS_UBSAN) + list(APPEND checked_compiler_options_ubsan "-fsanitize=undefined") + if(COMP_HAS_FSAN_FLOAT_DIVIDE_BY_ZERO) + list(APPEND checked_compiler_options_ubsan "-fsanitize=float-divide-by-zero") + endif() + if(COMP_HAS_FSAN_UNSIGNED_INTEGER_OVERFLOW) + list(APPEND checked_compiler_options_ubsan "-fsanitize=unsigned-integer-overflow") + endif() + if(COMP_HAS_FSAN_IMPLICIT_CONVERSION) + list(APPEND checked_compiler_options_ubsan "-fsanitize=implicit-conversion") + endif() + if(COMP_HAS_FSAN_NO_ENUM) + list(APPEND checked_compiler_options_ubsan "-fno-sanitize=enum") + endif() + if(COMP_HAS_FSAN_LOCAL_BOUNDS) + list(APPEND checked_compiler_options_ubsan "-fsanitize=local-bounds") + endif() endif() -if(COMP_HAS_FSAN_PTR_SUB) - list(APPEND checked_compiler_options_asan "-fsanitize=pointer-subtract" ) + +if(COMP_HAS_LSAN) + list(APPEND checked_compiler_options_lsan "-fsanitize=leak") endif() -if(COMP_HAS_FSAN_TRAP_ALL) - list(APPEND checked_compiler_options_asan "-fsanitize-trap=all" ) + +if(COMP_HAS_MSAN) + list(APPEND checked_compiler_options_msan "-fsanitize=memory") + if(COMP_HAS_F_SANITIZE_MEMORY_TRACK_ORIGINS) + list(APPEND checked_compiler_options_msan "-fsanitize=memory-track-origins") + endif() + if(COMP_HAS_F_PIE) + list(APPEND checked_compiler_options_msan "-fPIE") + endif() endif() +if(COMP_HAS_F_SANITIZE_SAFE_STACK) + list(APPEND checked_compiler_options_sanitize_harden "-fsanitize=safe-stack") +endif() if(COMP_HAS_FCF_PROTECTION_FULL) - list(APPEND checked_compiler_options_sanitize_other "-fcf-protection=full") + list(APPEND checked_compiler_options_sanitize_harden "-fcf-protection=full") endif() if(COMP_HAS_F_STACK_CHECK) - list(APPEND checked_compiler_options_sanitize_other "-fstack-check") + list(APPEND checked_compiler_options_sanitize_harden "-fstack-check") endif() if(COMP_HAS_F_STACK_PROTECTOR_ALL) - list(APPEND checked_compiler_options_sanitize_other "-fstack-protector-all") + list(APPEND checked_compiler_options_sanitize_harden "-fstack-protector-all") elseif(COMP_HAS_F_STACK_PROTECTOR_STRONG) - list(APPEND checked_compiler_options_sanitize_other "-fstack-protector-strong") + list(APPEND checked_compiler_options_sanitize_harden "-fstack-protector-strong") elseif(COMP_HAS_F_STACK_PROTECTOR) - list(APPEND checked_compiler_options_sanitize_other "-fstack-protector") + list(APPEND checked_compiler_options_sanitize_harden "-fstack-protector") endif() if(COMP_HAS_F_STACK_CLASH_PROTECTION) - list(APPEND checked_compiler_options_sanitize_other "-fstack-clash-protection") + list(APPEND checked_compiler_options_sanitize_harden "-fstack-clash-protection") endif() if(COMP_HAS_F_VTABLE_VERIFY_PREINIT) - list(APPEND checked_compiler_options_sanitize_other "-fvtable-verify=preinit") + list(APPEND checked_compiler_options_sanitize_harden "-fvtable-verify=preinit") endif() if(COMP_HAS_F_HARDEN_CFR) - list(APPEND checked_compiler_options_sanitize_other "-fharden-control-flow-redundancy") + list(APPEND checked_compiler_options_sanitize_harden "-fharden-control-flow-redundancy") endif() if(COMP_HAS_F_HARDCFR_CHECK_EXCEPTIONS) - list( - APPEND checked_compiler_options_sanitize_other "-fhardcfr-check-exceptions") + list(APPEND checked_compiler_options_sanitize_harden "-fhardcfr-check-exceptions") endif() if(COMP_HAS_W_USELESS_CAST) @@ -250,7 +334,6 @@ if( unset(COMPILER_SUPPORTS_NULL_DEREFERENCE CACHE) endif() - # ---- #[[ @@ -258,18 +341,37 @@ set(checked_compiler_options) set(checked_compiler_options_asan) #set(checked_compiler_options_ubsan) #set(checked_compiler_options_lsan) -set(checked_compiler_options_sanitize_other) +set(checked_compiler_options_sanitize_harden) set(checked_compiler_warnings) set(checked_compiler_warnings_disabled) set(checked_compiler_flags_msvc) ]] -message(STATUS "Adding the following conditional compiler options: ${checked_compiler_options}") -message(STATUS "Adding the following conditional compiler options for ASan: ${checked_compiler_options_asan}") -message(STATUS "Adding the following conditional compiler options for sanitizers: ${checked_compiler_options_sanitize_other}") -message(STATUS "Adding the following conditional compiler warnings: ${checked_compiler_warnings}") -message(STATUS "Adding the following conditional compiler warnings ignore options: ${checked_compiler_warnings_disabled}") +message(STATUS "Adding the following conditional compiler options: ${checked_compiler_options}.") +if(COMP_HAS_ASAN) + message(STATUS "Adding the following conditional compiler options for ASan: ${checked_compiler_options_asan}.") +endif() +if(COMP_HAS_UBSAN) + message(STATUS "Adding the following conditional compiler options for UBSan: ${checked_compiler_options_ubsan}.") +endif() +if(COMP_HAS_LSAN) + message(STATUS "Adding the following conditional compiler options for LSan: ${checked_compiler_options_lsan}.") +endif() + +if(COMP_HAS_MSAN) + message(STATUS "Adding the following conditional compiler options for MSan: ${checked_compiler_options_msan}.") +endif() + +message( + STATUS + "Adding the following conditional compiler options for hardening: ${checked_compiler_options_sanitize_harden}." +) +message(STATUS "Adding the following conditional compiler warnings: ${checked_compiler_warnings}.") +message( + STATUS + "Adding the following conditional compiler warnings ignore options: ${checked_compiler_warnings_disabled}." +) if(MSVC) - message(STATUS "Adding the following conditional compiler options: ${checked_compiler_flags_msvc}") + message(STATUS "Adding the following conditional compiler options: ${checked_compiler_flags_msvc}.") endif() From 4446409a08fe74e414097de0e68f12c17e690dd5 Mon Sep 17 00:00:00 2001 From: cbnolok Date: Sat, 21 Sep 2024 18:35:21 +0200 Subject: [PATCH 07/32] Reordered stypecast.h, moved some inlined CSString methods to the .cpp file. --- src/common/CException.h | 2 +- src/common/CLog.h | 5 +- src/common/sphere_library/CSString.cpp | 59 ++++++++++++ src/common/sphere_library/CSString.h | 106 +++++----------------- src/common/sphere_library/stypecast.h | 121 +++++++++++++------------ src/sphere/threads.cpp | 7 +- 6 files changed, 155 insertions(+), 145 deletions(-) diff --git a/src/common/CException.h b/src/common/CException.h index 7f2f9a0c8..a767cc666 100644 --- a/src/common/CException.h +++ b/src/common/CException.h @@ -6,7 +6,7 @@ #ifndef _INC_CEXCEPTION_H #define _INC_CEXCEPTION_H -#include "../sphere/threads.h" +//#include "../sphere/threads.h" #include "CLog.h" // ------------------------------------------------------------------- diff --git a/src/common/CLog.h b/src/common/CLog.h index f644e22fe..a362e5ccc 100644 --- a/src/common/CLog.h +++ b/src/common/CLog.h @@ -9,7 +9,10 @@ #include "sphere_library/CSFileText.h" #include "sphere_library/CSTime.h" #include "../sphere/ConsoleInterface.h" -#include + +namespace std { +class exception; // Forward declaration +} // ----------------------------- // CEventLog diff --git a/src/common/sphere_library/CSString.cpp b/src/common/sphere_library/CSString.cpp index 3e96295a9..8ae01f185 100644 --- a/src/common/sphere_library/CSString.cpp +++ b/src/common/sphere_library/CSString.cpp @@ -398,6 +398,65 @@ void CSString::FormatU64Val(uint64 uiVal) // CSString:: String operations +tchar CSString::GetAt(int nIndex) const +{ + ASSERT(nIndex >= 0); + ASSERT(nIndex <= m_iLength); // Allow to get the null char. + return m_pchData[nIndex]; +} + +tchar& CSString::ReferenceAt(int nIndex) +{ + ASSERT(nIndex >= 0); + ASSERT(nIndex < m_iLength); + return m_pchData[nIndex]; +} + +void CSString::MakeUpper() noexcept +{ + _strupr(m_pchData); +} + +void CSString::MakeLower() noexcept +{ + _strlwr(m_pchData); +} + +void CSString::Reverse() noexcept +{ + Str_Reverse(m_pchData); +} + +int CSString::Compare(lpctstr pStr) const noexcept +{ + return strcmp(m_pchData, pStr); +} + +int CSString::CompareNoCase(lpctstr pStr) const noexcept +{ + return strcmpi(m_pchData, pStr); +} + +int CSString::indexOf(tchar c) noexcept +{ + return indexOf(c, 0); +} + +int CSString::indexOf(const CSString& str) noexcept +{ + return indexOf(str, 0); +} + +int CSString::lastIndexOf(tchar c) noexcept +{ + return lastIndexOf(c, 0); +} + +int CSString::lastIndexOf(const CSString& str) noexcept +{ + return lastIndexOf(str, 0); +} + int CSString::indexOf(tchar c, int offset) noexcept { if ((offset < 0) || !IsValid()) diff --git a/src/common/sphere_library/CSString.h b/src/common/sphere_library/CSString.h index d68e70329..ecd7737b4 100644 --- a/src/common/sphere_library/CSString.h +++ b/src/common/sphere_library/CSString.h @@ -11,8 +11,6 @@ #endif // __MINGW32__ #include // needed for va_list -#include "sstring.h" - /** * @brief Custom String implementation. */ @@ -195,7 +193,7 @@ class CSString * @return character in position nIndex. */ [[nodiscard]] - inline tchar GetAt(int nIndex) const; + tchar GetAt(int nIndex) const; /** * @brief Gets the reference to character a specified position (0 based). @@ -203,7 +201,7 @@ class CSString * @return reference to character in position nIndex. */ [[nodiscard]] - inline tchar& ReferenceAt(int nIndex); + tchar& ReferenceAt(int nIndex); /** * @brief Puts a character in a specified position (0 based). @@ -273,17 +271,17 @@ class CSString /** * @brief Changes the capitalization of CSString to upper. */ - inline void MakeUpper() noexcept; + void MakeUpper() noexcept; /** * @brief Changes the capitalization of CSString to lower. */ - inline void MakeLower() noexcept; + void MakeLower() noexcept; /** * @brief Reverses the CSString. */ - inline void Reverse() noexcept; + void Reverse() noexcept; ///@} @@ -492,7 +490,7 @@ class CSString * @return <0 if the first character that not match has lower value in CSString than in pStr. 0 if the contents of both are equal. >0 if the first character that does not match has greater value in CSString than pStr. */ [[nodiscard]] - inline int Compare(lpctstr pStr) const noexcept; + int Compare(lpctstr pStr) const noexcept; /** * @brief Compares the CSString to string pStr (case insensitive) (_strcmpi wrapper). @@ -505,7 +503,7 @@ class CSString * @return <0 if the first character that not match has lower value in CSString than in pStr. 0 if the contents of both are equal. >0 if the first character that does not match has greater value in CSString than pStr. */ [[nodiscard]] - inline int CompareNoCase(lpctstr pStr) const noexcept; + int CompareNoCase(lpctstr pStr) const noexcept; /** * @brief Gets the internal pointer. @@ -523,7 +521,7 @@ class CSString * @return position of the character in CSString if any, -1 otherwise. */ [[nodiscard]] - inline int indexOf(tchar c) noexcept; + int indexOf(tchar c) noexcept; /** * @brief Look for the first occurence of c in CSString from a position. @@ -540,7 +538,7 @@ class CSString * @return position of the substring in CSString if any, -1 otherwise. */ [[nodiscard]] - inline int indexOf(const CSString& str) noexcept; + int indexOf(const CSString& str) noexcept; /** * @brief Look for the first occurence of a substring in CSString from a position. @@ -557,7 +555,7 @@ class CSString * @return position of the character in CSString if any, -1 otherwise. */ [[nodiscard]] - inline int lastIndexOf(tchar c) noexcept; + int lastIndexOf(tchar c) noexcept; /** * @brief Look for the last occurence of c in CSString from a position to the end. @@ -574,7 +572,7 @@ class CSString * @return position of the substring in CSString if any, -1 otherwise. */ [[nodiscard]] - inline int lastIndexOf(const CSString& str) noexcept; + int lastIndexOf(const CSString& str) noexcept; /** * @brief Look for the last occurence of a substring in CSString from a position to the end. @@ -605,7 +603,12 @@ CSString::CSString(CSString&& s) noexcept : *this = std::move(s); // Call the move assignment operator } -CSString CSString::EmptyNew() +CSString::operator lpctstr() const noexcept +{ + return GetBuffer(); +} + +CSString CSString::EmptyNew() // static { return CSString(false); } @@ -625,90 +628,27 @@ int CSString::GetCapacity() const noexcept return m_iMaxLength; } -tchar CSString::operator[](int nIndex) const -{ - return GetAt(nIndex); -} - -tchar& CSString::operator[](int nIndex) -{ - return ReferenceAt(nIndex); -} - -tchar CSString::GetAt(int nIndex) const -{ - ASSERT(nIndex >= 0); - ASSERT(nIndex <= m_iLength); // Allow to get the null char. - return m_pchData[nIndex]; -} - -tchar& CSString::ReferenceAt(int nIndex) -{ - ASSERT(nIndex >= 0); - ASSERT(nIndex < m_iLength); - return m_pchData[nIndex]; -} - -void CSString::MakeUpper() noexcept -{ - _strupr(m_pchData); -} - -void CSString::MakeLower() noexcept -{ - _strlwr(m_pchData); -} - -void CSString::Reverse() noexcept -{ - Str_Reverse(m_pchData); -} - -CSString::operator lpctstr() const noexcept -{ - return GetBuffer(); -} - -int CSString::Compare(lpctstr pStr) const noexcept -{ - return strcmp(m_pchData, pStr); -} - -int CSString::CompareNoCase(lpctstr pStr) const noexcept -{ - return strcmpi(m_pchData, pStr); -} - lpctstr CSString::GetBuffer() const noexcept { - return m_pchData; + return m_pchData; } /* lptstr CSString::GetBuffer() noexcept { - return m_pchData; + return m_pchData; } */ -int CSString::indexOf(tchar c) noexcept -{ - return indexOf(c, 0); -} - -int CSString::indexOf(const CSString& str) noexcept +tchar CSString::operator[](int nIndex) const { - return indexOf(str, 0); + return GetAt(nIndex); } -int CSString::lastIndexOf(tchar c) noexcept +tchar& CSString::operator[](int nIndex) { - return lastIndexOf(c, 0); + return ReferenceAt(nIndex); } -int CSString::lastIndexOf(const CSString& str) noexcept -{ - return lastIndexOf(str, 0); -} #endif // _INC_CSSTRING_H diff --git a/src/common/sphere_library/stypecast.h b/src/common/sphere_library/stypecast.h index d450be93b..ebbade7cb 100644 --- a/src/common/sphere_library/stypecast.h +++ b/src/common/sphere_library/stypecast.h @@ -1,6 +1,7 @@ #ifndef _INC_STYPECAST_H #define _INC_STYPECAST_H +//#include "../CLog.h" #include #include #include @@ -71,54 +72,6 @@ constexpr Tout enum_alias_cast(const Tin a) noexcept } -/* Unsigned (and size_t) to signed, clamping. */ - -[[nodiscard]] constexpr -int8 i8_from_u8_clamping(const uint8 a) noexcept -{ - return (a > (uint8_t)std::numeric_limits::max()) ? std::numeric_limits::max() : (int8_t)a; -} - -[[nodiscard]] constexpr -int16 i16_from_u16_clamping(const uint16 a) noexcept -{ - return (a > (uint16_t)std::numeric_limits::max()) ? std::numeric_limits::max() : (int16_t)a; -} - -[[nodiscard]] constexpr -int32 i32_from_u32_clamping(const uint32 a) noexcept -{ - return (a > (uint32_t)std::numeric_limits::max()) ? std::numeric_limits::max() : (int32_t)a; -} - -[[nodiscard]] constexpr -int64 i64_from_u64_clamping(const uint64 a) noexcept -{ - return (a > (uint64_t)std::numeric_limits::max()) ? std::numeric_limits::max() : (int64_t)a; -} - -[[nodiscard]] constexpr -int32 i32_from_usize_clamping(const size_t a) noexcept -{ - return (a > (size_t)std::numeric_limits::max()) ? std::numeric_limits::max() : (int32_t)a; -} - -[[nodiscard]] constexpr -int64 i64_from_usize_clamping(const size_t a) noexcept -{ - return (a > (size_t)std::numeric_limits::max()) ? std::numeric_limits::max() : (int64_t)a; -} - -[[nodiscard]] constexpr -uint32 u32_from_usize_clamping(const size_t a) noexcept -{ - if constexpr (sizeof(size_t) == 8) - return (a > (size_t)std::numeric_limits::max()) ? std::numeric_limits::max() : (uint32_t)a; - else - return a; -} - - /* Promotion and narrowing of numbers to a same sign greater/smaller data type */ // Explicitly promote to a larger type or narrow to a smaller type, instead of inattentive raw casts. @@ -456,11 +409,59 @@ uint32 usize_narrow_u32_checked(const size_t a) } +/* Unsigned (and size_t) to signed, clamping. */ + +[[nodiscard]] constexpr + int8 i8_from_u8_clamping(const uint8 a) noexcept +{ + return (a > (uint8_t)std::numeric_limits::max()) ? std::numeric_limits::max() : (int8_t)a; +} + +[[nodiscard]] constexpr + int16 i16_from_u16_clamping(const uint16 a) noexcept +{ + return (a > (uint16_t)std::numeric_limits::max()) ? std::numeric_limits::max() : (int16_t)a; +} + +[[nodiscard]] constexpr + int32 i32_from_u32_clamping(const uint32 a) noexcept +{ + return (a > (uint32_t)std::numeric_limits::max()) ? std::numeric_limits::max() : (int32_t)a; +} + +[[nodiscard]] constexpr + int64 i64_from_u64_clamping(const uint64 a) noexcept +{ + return (a > (uint64_t)std::numeric_limits::max()) ? std::numeric_limits::max() : (int64_t)a; +} + +[[nodiscard]] constexpr + int32 i32_from_usize_clamping(const size_t a) noexcept +{ + return (a > (size_t)std::numeric_limits::max()) ? std::numeric_limits::max() : (int32_t)a; +} + +[[nodiscard]] constexpr + int64 i64_from_usize_clamping(const size_t a) noexcept +{ + return (a > (size_t)std::numeric_limits::max()) ? std::numeric_limits::max() : (int64_t)a; +} + +[[nodiscard]] constexpr + uint32 u32_from_usize_clamping(const size_t a) noexcept +{ + if constexpr (sizeof(size_t) == 8) + return (a > (size_t)std::numeric_limits::max()) ? std::numeric_limits::max() : (uint32_t)a; + else + return a; +} + + /* Unsigned (and size_t) to signed, checked for overflows. */ // Convert an 8 bits unsigned value to signed and ASSERT (because you're reasonably sure but not absolutely certain) that it will fit into its signed datatype counterpart (unsigned variables can store greater values than signed ones). [[nodiscard]] inline -int8 i8_from_u8_checked(const uint8 a) // not clamping/capping + int8 i8_from_u8_checked(const uint8 a) // not clamping/capping { ASSERT(a <= (uint8_t)std::numeric_limits::max()); return static_cast(a); @@ -469,7 +470,7 @@ template int8 i8_from_u8_checked(T) = delete; // disable implicit t // Convert a 16 bits unsigned value to signed and ASSERT (because you're reasonably sure but not absolutely certain) that it will fit into its signed datatype counterpart (unsigned variables can store greater values than signed ones). [[nodiscard]] inline -int16 i16_from_u16_checked(const uint16 a) // not clamping/capping + int16 i16_from_u16_checked(const uint16 a) // not clamping/capping { ASSERT(a <= (uint16_t)std::numeric_limits::max()); return static_cast(a); @@ -477,7 +478,7 @@ int16 i16_from_u16_checked(const uint16 a) // not clamping/capping template int16 i16_from_u16_checked(T) = delete; // disable implicit type conversion for the input argument [[nodiscard]] inline -int16 i16_from_u32_checked(const uint32 a) // not clamping/capping + int16 i16_from_u32_checked(const uint32 a) // not clamping/capping { ASSERT(a <= (uint32_t)std::numeric_limits::max()); return static_cast(a); @@ -485,7 +486,7 @@ int16 i16_from_u32_checked(const uint32 a) // not clamping/capping template int16 i16_from_u32_checked(T) = delete; // disable implicit type conversion for the input argument [[nodiscard]] inline -int16 i16_from_u64_checked(const uint64 a) // not clamping/capping + int16 i16_from_u64_checked(const uint64 a) // not clamping/capping { ASSERT(a <= (uint64_t)std::numeric_limits::max()); return static_cast(a); @@ -494,7 +495,7 @@ template int16 i16_from_u64_checked(T) = delete; // disable implici // Convert a 32 bits unsigned value to signed and ASSERT (because you're reasonably sure but not absolutely certain) that it will fit into its signed datatype counterpart (unsigned variables can store greater values than signed ones). [[nodiscard]] inline -int32 i32_from_u32_checked(const uint32 a) // not clamping/capping + int32 i32_from_u32_checked(const uint32 a) // not clamping/capping { ASSERT(a <= (uint32_t)std::numeric_limits::max()); return static_cast(a); @@ -502,7 +503,7 @@ int32 i32_from_u32_checked(const uint32 a) // not clamping/capping template int32 i32_from_u32_checked(T) = delete; // disable implicit type conversion for the input argument [[nodiscard]] inline -int32 i32_from_u64_checked(const uint64 a) // not clamping/capping + int32 i32_from_u64_checked(const uint64 a) // not clamping/capping { ASSERT(a <= (uint64_t)std::numeric_limits::max()); return static_cast(a); @@ -511,7 +512,7 @@ template int32 i32_from_u64_checked(T) = delete; // disable implici // Convert a 64 bits unsigned value to signed and ASSERT (because you're reasonably sure but not absolutely certain) that it will fit into its signed datatype counterpart (unsigned variables can store greater values than signed ones). [[nodiscard]] inline -int64 i64_from_u64_checked(const uint64 a) // not clamping/capping + int64 i64_from_u64_checked(const uint64 a) // not clamping/capping { ASSERT(a <= (uint64_t)std::numeric_limits::max()); return static_cast(a); @@ -521,7 +522,7 @@ template int64 i64_from_u64_checked(T) = delete; // disable implici // size_t conversions [[nodiscard]] inline -int8 i8_from_usize_checked(const size_t a) // not clamping/capping + int8 i8_from_usize_checked(const size_t a) // not clamping/capping { #if SIZE_MAX == UINT64_MAX return n64_narrow_n8_checked(a); @@ -535,7 +536,7 @@ template int8 i8_from_usize_checked(T) = delete; // disable implici [[nodiscard]] inline -int16 i16_from_usize_checked(const size_t a) // not clamping/capping + int16 i16_from_usize_checked(const size_t a) // not clamping/capping { #if SIZE_MAX == UINT64_MAX return n64_narrow_n16_checked(a); @@ -548,7 +549,7 @@ int16 i16_from_usize_checked(const size_t a) // not clamping/capping template int16 i16_from_usize_checked(T) = delete; // disable implicit type conversion for the input argument [[nodiscard]] inline -int32 i32_from_usize_checked(const size_t a) // not clamping/capping + int32 i32_from_usize_checked(const size_t a) // not clamping/capping { #if SIZE_MAX == UINT64_MAX return i32_from_u32_clamping(n64_narrow_n32_checked(a)); @@ -561,7 +562,7 @@ int32 i32_from_usize_checked(const size_t a) // not clamping/capping template int32 i32_from_usize_checked(T) = delete; // disable implicit type conversion for the input argument [[nodiscard]] inline -int64 i64_from_usize_checked(const size_t a) // not clamping/capping + int64 i64_from_usize_checked(const size_t a) // not clamping/capping { #if SIZE_MAX == UINT64_MAX return i64_from_u64_checked(n_alias_cast(a)); @@ -574,4 +575,6 @@ int64 i64_from_usize_checked(const size_t a) // not clamping/capping template int64 i64_from_usize_checked(T) = delete; // disable implicit type conversion for the input argument + + #endif // _INC_STYPECAST_H diff --git a/src/sphere/threads.cpp b/src/sphere/threads.cpp index 201514c2a..5a319fdf9 100644 --- a/src/sphere/threads.cpp +++ b/src/sphere/threads.cpp @@ -114,10 +114,11 @@ void IThread::setThreadName(const char* name) auto athr = static_cast(ThreadHolder::get().current()); ASSERT(athr); +#ifdef _DEBUG g_Log.Event(LOGF_CONSOLE_ONLY|LOGM_DEBUG|LOGL_EVENT, "Setting thread (ThreadHolder ID %d, internal name '%s') system name: '%s'.\n", athr->m_threadHolderId, athr->getName(), name_trimmed); - +#endif athr->overwriteInternalThreadName(name_trimmed); } @@ -278,6 +279,7 @@ void ThreadHolder::push(IThread *thread) noexcept RaiseImmediateAbort(); } +#ifdef _DEBUG if (dynamic_cast(thread)) { // Too early in the init process to use the console... @@ -290,6 +292,7 @@ void ThreadHolder::push(IThread *thread) noexcept "Registered thread '%s' with ThreadHolder ID %d.\n", thread->getName(), thread->m_threadHolderId); } +#endif } /* @@ -712,9 +715,11 @@ void AbstractThread::onStart() if (isActive()) // This thread has actually been spawned and the code is executing on a different thread setThreadName(getName()); +#ifdef _DEBUG g_Log.Event(LOGM_DEBUG|LOGL_EVENT|LOGF_CONSOLE_ONLY, "Started thread '%s' with ThreadHolder ID %d and system ID %" PRIu64 ".\n", getName(), m_threadHolderId, (uint64)m_threadSystemId); +#endif } void AbstractThread::setPriority(IThread::Priority pri) From e3ba11d7ec360555a397afc56a9f591f449bcff0 Mon Sep 17 00:00:00 2001 From: cbnolok Date: Sat, 21 Sep 2024 18:35:30 +0200 Subject: [PATCH 08/32] Updated .clang-format --- .clang-format | 30 +++++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/.clang-format b/.clang-format index b993d79f0..7e32248d7 100644 --- a/.clang-format +++ b/.clang-format @@ -13,9 +13,14 @@ ColumnLimit: 160 AlignAfterOpenBracket: AlwaysBreak AlignConsecutiveAssignments: true AlignConsecutiveDeclarations: false -#AlignEscapedNewlinesLeft: false -AlignTrailingComments: true - +#AlignConsecutiveTableGenDefinitionColons: +# Enabled: true +# AcrossEmptyLines: true +# AcrossComments: false +AlignEscapedNewlines: Left # LeftWithLastLine # Right +AlignTrailingComments: + Kind: Always + OverEmptyLines: 1 DerivePointerAlignment: false PointerAlignment: Right @@ -48,12 +53,15 @@ BraceWrapping: Cpp11BracedListStyle: false ##-- Line breaks -AlwaysBreakAfterDefinitionReturnType: None +#AllowBreakBeforeNoexceptSpecifier: OnlyWithParen +AlwaysBreakAfterDefinitionReturnType: All AlwaysBreakAfterReturnType: None AlwaysBreakBeforeMultilineStrings: true +BreakAfterAttributes: Always AlwaysBreakTemplateDeclarations: true BreakAfterJavaFieldAnnotations: false BreakBeforeBinaryOperators: None +BreakBeforeConceptDeclarations: Always BreakConstructorInitializers: AfterColon #BreakInheritanceList: AfterColon BreakBeforeTernaryOperators: false @@ -70,6 +78,8 @@ LambdaBodyIndentation: Signature NamespaceIndentation: Inner ##-- Spaces in/between statements/etc +MaxEmptyLinesToKeep: 2 +SeparateDefinitionBlocks: Always SpaceAfterCStyleCast: false SpaceAfterTemplateKeyword: false #SpaceAroundPointerQualifiers: Left @@ -85,19 +95,25 @@ SpacesInContainerLiterals: false SpacesInParentheses: false SpacesInSquareBrackets: false + +##-- Code sections/blocks +#MacroBlockBegin: [regex -> EXC_TRY...] +#MacroBlockEnd: +FixNamespaceComments: true +ShortNamespaceLines: 2 +#StatementMacros: [-> ASSERT?] + ##-- Misc AllowAllParametersOfDeclarationOnNextLine: true AccessModifierOffset: -4 BinPackArguments: false BinPackParameters: false -BreakAfterAttributes: Always -ExperimentalAutoDetectBinPacking: false ConstructorInitializerAllOnOneLineOrOnePerLine: false DisableFormat: false +ExperimentalAutoDetectBinPacking: false InsertNewlineAtEOF: true KeepEmptyLinesAtTheStartOfBlocks: false ReflowComments: false -SeparateDefinitionBlocks: Always #-- Include order #IncludeIsMainRegex: '$?' From 639368611da5776e8b3f6a42064c58bab0801531 Mon Sep 17 00:00:00 2001 From: cbnolok Date: Mon, 23 Sep 2024 18:28:33 +0200 Subject: [PATCH 09/32] Added some static qualifiers, moved some functions from spheresvr.cpp to CServer.cpp --- src/common/CDataBase.cpp | 4 +- src/common/CException.cpp | 14 +- src/common/CExpression.cpp | 6 +- src/common/CFloatMath.cpp | 2 +- src/common/crypto/CBCrypt.cpp | 6 +- src/common/sqlite/SQLite.cpp | 8 +- src/common/sqlite/SQLite.h | 6 +- src/game/CServer.cpp | 297 +++++++++++++++++++++++++++++++++ src/game/CServerDef.cpp | 6 +- src/game/CWorld.cpp | 10 +- src/game/chars/CChar.cpp | 6 +- src/game/spheresvr.cpp | 303 +--------------------------------- src/game/triggers.cpp | 20 +-- src/network/PingServer.cpp | 2 +- src/network/PingServer.h | 5 +- src/sphere/asyncdb.h | 3 + src/sphere/threads.cpp | 1 + 17 files changed, 350 insertions(+), 349 deletions(-) diff --git a/src/common/CDataBase.cpp b/src/common/CDataBase.cpp index 3266a643e..4f56d3a34 100644 --- a/src/common/CDataBase.cpp +++ b/src/common/CDataBase.cpp @@ -2,15 +2,13 @@ #include "../game/CServer.h" #include "../game/CServerTime.h" #include "../sphere/asyncdb.h" -#include "resource/sections/CResourceNamedDef.h" +#include "resource/sections/CResourceNamedDef.h" // Needed because it was only forward declared. #include "CLog.h" #include "CException.h" #include "CExpression.h" #include "CScriptTriggerArgs.h" #include "CDataBase.h" -extern CDataBaseAsyncHelper g_asyncHdb; - CDataBase::CDataBase() { diff --git a/src/common/CException.cpp b/src/common/CException.cpp index a29834e7c..8c92641b1 100644 --- a/src/common/CException.cpp +++ b/src/common/CException.cpp @@ -70,7 +70,7 @@ void SetAbortImmediate(bool on) noexcept { *_GetAbortImmediate() = on; } -bool IsAbortImmediate() noexcept +static bool IsAbortImmediate() noexcept { return *_GetAbortImmediate(); } @@ -225,7 +225,7 @@ void Assert_Fail( lpctstr pExp, lpctstr pFile, long long llLine ) throw CAssert(LOGL_CRIT, pExp, pFile, llLine); } -void _cdecl Sphere_Purecall_Handler() +static void _cdecl Sphere_Purecall_Handler() { // catch this special type of C++ exception as well. Assert_Fail("purecall", "unknown", 1); @@ -273,7 +273,7 @@ void SetExceptionTranslator() } #ifndef _WIN32 -void _cdecl Signal_Hangup(int sig = 0) noexcept // If shutdown is initialized +static void _cdecl Signal_Hangup(int sig = 0) noexcept // If shutdown is initialized { UnreferencedParameter(sig); @@ -292,7 +292,7 @@ void _cdecl Signal_Hangup(int sig = 0) noexcept // If shutdown is initialized g_Serv.SetExitFlag(SIGHUP); } -void _cdecl Signal_Terminate(int sig = 0) noexcept // If shutdown is initialized +static void _cdecl Signal_Terminate(int sig = 0) noexcept // If shutdown is initialized { g_Log.Event(LOGL_FATAL, "Server Unstable: %s signal received\n", strsignal(sig)); @@ -346,7 +346,7 @@ void _cdecl Signal_Terminate(int sig = 0) noexcept // If shutdown is initialized //exit(EXIT_FAILURE); // Having set the exit flag, all threads "should" terminate cleanly. } -void _cdecl Signal_Break(int sig = 0) // signal handler attached when using secure mode +static void _cdecl Signal_Break(int sig = 0) // signal handler attached when using secure mode { // Shouldn't be needed, since gdb consumes the signals itself and this code won't be executed //#ifdef _DEBUG @@ -367,7 +367,7 @@ void _cdecl Signal_Break(int sig = 0) // signal handler attached when using sec } } -void _cdecl Signal_Illegal_Instruction(int sig = 0) +static void _cdecl Signal_Illegal_Instruction(int sig = 0) { #ifdef THREAD_TRACK_CALLSTACK StackDebugInformation::freezeCallStack(true); @@ -394,7 +394,7 @@ void _cdecl Signal_Illegal_Instruction(int sig = 0) throw CSError(LOGL_FATAL, sig, strsignal(sig)); } -void _cdecl Signal_Children(int sig = 0) +static void _cdecl Signal_Children(int sig = 0) { UnreferencedParameter(sig); while (waitpid((pid_t)(-1), nullptr, WNOHANG) > 0) {} diff --git a/src/common/CExpression.cpp b/src/common/CExpression.cpp index 208a57e58..550a177ad 100644 --- a/src/common/CExpression.cpp +++ b/src/common/CExpression.cpp @@ -125,7 +125,7 @@ int StrncpyCharBytesWritten(int iBytesToWrite, size_t uiBufSize, bool fPrintErro return (uiBufSize > 1) ? int(uiBufSize - 1) : 0; // Bytes written, excluding the string terminator. } -llong power(llong base, llong level) +static llong cexpression_power(llong base, llong level) { double rc = pow((double)base, (double)level); return (llong)rc; @@ -1057,7 +1057,7 @@ llong CExpression::GetValMath( llong llVal, lpctstr & pExpr ) llValSecond = GetVal(pExpr); if (llVal < 0) { - llVal = power(llVal, llValSecond); + llVal = cexpression_power(llVal, llValSecond); break; } else if ((llVal == 0) && (llValSecond <= 0)) //The information from https://en.cppreference.com/w/cpp/numeric/math/pow says if both input are 0, it can cause errors too. @@ -1065,7 +1065,7 @@ llong CExpression::GetValMath( llong llVal, lpctstr & pExpr ) g_Log.EventError("Power of zero with zero or negative exponent is undefined.\n"); break; } - llVal = power(llVal, llValSecond); + llVal = cexpression_power(llVal, llValSecond); break; } diff --git a/src/common/CFloatMath.cpp b/src/common/CFloatMath.cpp index 1cfd8afe1..8b0238ce6 100644 --- a/src/common/CFloatMath.cpp +++ b/src/common/CFloatMath.cpp @@ -19,7 +19,7 @@ CSString CFloatMath::FloatMath(lpctstr& Expr) } -short int _iReentrant_Count = 0; +static thread_local short int _iReentrant_Count = 0; realtype CFloatMath::MakeFloatMath( lpctstr & Expr ) { diff --git a/src/common/crypto/CBCrypt.cpp b/src/common/crypto/CBCrypt.cpp index e917d422c..ef39b8cca 100644 --- a/src/common/crypto/CBCrypt.cpp +++ b/src/common/crypto/CBCrypt.cpp @@ -61,7 +61,7 @@ static int timing_safe_strcmp(const char *str1, const char *str2) * nonzero otherwise. * */ -int bcrypt_gensalt(const char* prefix, int factor, char salt[BCRYPT_HASHSIZE]) +static int bcrypt_gensalt(const char* prefix, int factor, char salt[BCRYPT_HASHSIZE]) { #define RANDBYTES (16) //char input[RANDBYTES]; @@ -94,7 +94,7 @@ int bcrypt_gensalt(const char* prefix, int factor, char salt[BCRYPT_HASHSIZE]) * The return value is zero if the password could be hashed and nonzero * otherwise. */ -int bcrypt_hashpw(const char *passwd, const char salt[BCRYPT_HASHSIZE], char hash[BCRYPT_HASHSIZE]) +static int bcrypt_hashpw(const char *passwd, const char salt[BCRYPT_HASHSIZE], char hash[BCRYPT_HASHSIZE]) { char *aux; aux = crypt_rn(passwd, salt, hash, BCRYPT_HASHSIZE); @@ -110,7 +110,7 @@ int bcrypt_hashpw(const char *passwd, const char salt[BCRYPT_HASHSIZE], char has * passwords don't match. * */ -int bcrypt_checkpw(const char *passwd, const char hash[BCRYPT_HASHSIZE]) +static int bcrypt_checkpw(const char *passwd, const char hash[BCRYPT_HASHSIZE]) { int ret; char outhash[BCRYPT_HASHSIZE]; diff --git a/src/common/sqlite/SQLite.cpp b/src/common/sqlite/SQLite.cpp index f2fa7078e..2414c39e5 100644 --- a/src/common/sqlite/SQLite.cpp +++ b/src/common/sqlite/SQLite.cpp @@ -702,10 +702,10 @@ SQLiteTablePtr::SQLiteTablePtr( SQLiteTable * pTable ) m_pTable = pTable; } -SQLiteTablePtr::SQLiteTablePtr( const SQLiteTablePtr & cTablePtr ) +SQLiteTablePtr::SQLiteTablePtr( SQLiteTablePtr & cTablePtr ) { m_pTable=cTablePtr.m_pTable; - ((SQLiteTablePtr *)&cTablePtr)->m_pTable=nullptr; + cTablePtr.m_pTable=nullptr; } SQLiteTablePtr::~SQLiteTablePtr() @@ -714,12 +714,12 @@ SQLiteTablePtr::~SQLiteTablePtr() delete m_pTable; } -void SQLiteTablePtr::operator =( const SQLiteTablePtr & cTablePtr ) +void SQLiteTablePtr::operator =( SQLiteTablePtr & cTablePtr ) { if (m_pTable) delete m_pTable; m_pTable=cTablePtr.m_pTable; - ((SQLiteTablePtr *)&cTablePtr)->m_pTable=nullptr; + cTablePtr.m_pTable=nullptr; } SQLiteTable * SQLiteTablePtr::Detach() diff --git a/src/common/sqlite/SQLite.h b/src/common/sqlite/SQLite.h index e06b1a910..5386bba5f 100644 --- a/src/common/sqlite/SQLite.h +++ b/src/common/sqlite/SQLite.h @@ -181,7 +181,8 @@ class SQLiteTablePtr // If you have a previous table connected to this class, // you do not have to worry, // it will commit suicide before eating the new table. - SQLiteTablePtr( const SQLiteTablePtr & cTablePtr ); + SQLiteTablePtr( SQLiteTablePtr & cTablePtr ); + SQLiteTablePtr( const SQLiteTablePtr & cTablePtr ) = delete; // Destructor... virtual ~SQLiteTablePtr(); @@ -191,7 +192,8 @@ class SQLiteTablePtr // If you have a previous table connected to this class, // you do not have to worry, // it will commit suicide before eating the new table. - void operator =(const SQLiteTablePtr & cTablePtr); + void operator =(SQLiteTablePtr & cTablePtr); + void operator =(const SQLiteTablePtr & cTablePtr) = delete; // Functor operator, will de-reference the m_pTable member. // WARNING: Use with care! Check for non-null m_pTable first! diff --git a/src/game/CServer.cpp b/src/game/CServer.cpp index 354749a43..cbbb47a35 100644 --- a/src/game/CServer.cpp +++ b/src/game/CServer.cpp @@ -35,6 +35,303 @@ #include +//****************************************************** + +static void dword_q_sort(dword *numbers, dword left, dword right) +{ + dword pivot, l_hold, r_hold; + + l_hold = left; + r_hold = right; + pivot = numbers[left]; + while (left < right) + { + while ((numbers[right] >= pivot) && (left < right)) right--; + if (left != right) + { + numbers[left] = numbers[right]; + left++; + } + while ((numbers[left] <= pivot) && (left < right)) left++; + if (left != right) + { + numbers[right] = numbers[left]; + right--; + } + } + numbers[left] = pivot; + pivot = left; + left = l_hold; + right = r_hold; + if (left < pivot) + dword_q_sort(numbers, left, pivot-1); + if (right > pivot) + dword_q_sort(numbers, pivot+1, right); +} + +static void defragSphere(char *path) +{ + ASSERT(path != nullptr); + + constexpr size_t mb10 = 10*1024*1024; + constexpr size_t mb5 = 5*1024*1024; + + CSFileText inf; + CSFile ouf; + char file_buf[1024]; + char path_buf[_MAX_PATH], path_buf_2[_MAX_PATH]; + char *str_ptr = nullptr, *str_ptr_2 = nullptr; + + g_Log.Event(LOGM_INIT, "Defragmentation (UID alteration) of " SPHERE_TITLE " saves.\n" + "Use it on your risk and if you know what you are doing since it can possibly harm your server.\n" + "The process can take up to several hours depending on the CPU you have.\n" + "After finished, you will have your '" SPHERE_FILE "*.scp' files converted and saved as '" SPHERE_FILE "*.scp.new'.\n"); + + // UID_O_INDEX_MASK ? + constexpr dword MAX_UID = 40'000'000U; // limit to 40mln of objects, takes 40mln*4bytes ~= 160mb + + dword dwIdxUID = 0; + dword* puids = (dword*)calloc(MAX_UID, sizeof(dword)); + for ( uint i = 0; i < 3; ++i ) + { + Str_CopyLimitNull(path_buf, path, sizeof(path_buf)); + if ( i == 0 ) strcat(path_buf, SPHERE_FILE "statics" SPHERE_SCRIPT); + else if ( i == 1 ) strcat(path_buf, SPHERE_FILE "world" SPHERE_SCRIPT); + else strcat(path_buf, SPHERE_FILE "chars" SPHERE_SCRIPT); + + g_Log.Event(LOGM_INIT, "Reading current UIDs: %s\n", path_buf); + if ( !inf.Open(path_buf, OF_READ|OF_TEXT|OF_DEFAULTMODE) ) + { + g_Log.Event(LOGM_INIT, "Cannot open file for reading. Skipped!\n"); + continue; + } + size_t uiBytesRead = 0, uiTotalMb = 0; + while ((dwIdxUID < MAX_UID) && !feof(inf._pStream)) + { + fgets(file_buf, sizeof(file_buf), inf._pStream); + uiBytesRead += strlen(file_buf); + if ( uiBytesRead > mb10 ) + { + uiBytesRead -= mb10; + uiTotalMb += 10; + g_Log.Event(LOGM_INIT, "Total read %" PRIuSIZE_T " Mb\n", uiTotalMb); + } + if (( file_buf[0] == 'S' ) && ( strstr(file_buf, "SERIAL=") == file_buf )) + { + str_ptr = file_buf + 7; + str_ptr_2 = str_ptr; + while (*str_ptr_2 && (*str_ptr_2 != '\r') && (*str_ptr_2 != '\n')) + { + ++str_ptr_2; + } + *str_ptr_2 = 0; + + // prepare new uid + *(str_ptr-1) = '0'; + *str_ptr = 'x'; + --str_ptr; + puids[dwIdxUID++] = strtoul(str_ptr, &str_ptr_2, 16); + } + } + inf.Close(); + } + const dword dwTotalUIDs = dwIdxUID; + g_Log.Event(LOGM_INIT, "Totally having %" PRIu32 " unique objects (UIDs), latest: 0%x\n", dwTotalUIDs, puids[dwTotalUIDs-1]); + + g_Log.Event(LOGM_INIT, "Quick-Sorting the UIDs array...\n"); + dword_q_sort(puids, 0, dwTotalUIDs -1); + + for ( uint i = 0; i < 5; ++i ) + { + Str_CopyLimitNull(path_buf, path, sizeof(path_buf)); + if ( !i ) strcat(path_buf, SPHERE_FILE "accu.scp"); + else if ( i == 1 ) strcat(path_buf, SPHERE_FILE "chars" SPHERE_SCRIPT); + else if ( i == 2 ) strcat(path_buf, SPHERE_FILE "data" SPHERE_SCRIPT); + else if ( i == 3 ) strcat(path_buf, SPHERE_FILE "world" SPHERE_SCRIPT); + else if ( i == 4 ) strcat(path_buf, SPHERE_FILE "statics" SPHERE_SCRIPT); + g_Log.Event(LOGM_INIT, "Updating UID-s in %s to %s.new\n", path_buf, path_buf); + if ( !inf.Open(path_buf, OF_READ|OF_TEXT|OF_DEFAULTMODE) ) + { + g_Log.Event(LOGM_INIT, "Cannot open file for reading. Skipped!\n"); + continue; + } + Str_ConcatLimitNull(path_buf, ".new", sizeof(path_buf)); + if ( !ouf.Open(path_buf, OF_WRITE|OF_CREATE|OF_DEFAULTMODE) ) + { + g_Log.Event(LOGM_INIT, "Cannot open file for writing. Skipped!\n"); + continue; + } + + size_t uiBytesRead = 0, uiTotalMb = 0; + while ( inf.ReadString(file_buf, sizeof(file_buf)) ) + { + dwIdxUID = (dword)strlen(file_buf); + if (dwIdxUID > (ARRAY_COUNT(file_buf) - 3)) + dwIdxUID = ARRAY_COUNT(file_buf) - 3; + + file_buf[dwIdxUID] = file_buf[dwIdxUID +1] = file_buf[dwIdxUID +2] = 0; // just to be sure to be in line always + // NOTE: it is much faster than to use memcpy to clear before reading + bool fSpecial = false; + uiBytesRead += dwIdxUID; + if ( uiBytesRead > mb5 ) + { + uiBytesRead -= mb5; + uiTotalMb += 5; + g_Log.Event(LOGM_INIT, "Total processed %" PRIuSIZE_T " Mb\n", uiTotalMb); + } + str_ptr = file_buf; + + // Note 28-Jun-2004 + // mounts seems having ACTARG1 > 0x30000000. The actual UID is ACTARG1-0x30000000. The + // new also should be new+0x30000000. need investigation if this can help making mounts + // not to disappear after the defrag + if (( file_buf[0] == 'A' ) && ( strstr(file_buf, "ACTARG1=0") == file_buf )) // ACTARG1= + str_ptr += 8; + else if (( file_buf[0] == 'C' ) && ( strstr(file_buf, "CONT=0") == file_buf )) // CONT= + str_ptr += 5; + else if (( file_buf[0] == 'C' ) && ( strstr(file_buf, "CHARUID=0") == file_buf )) // CHARUID= + str_ptr += 8; + else if (( file_buf[0] == 'L' ) && ( strstr(file_buf, "LASTCHARUID=0") == file_buf )) // LASTCHARUID= + str_ptr += 12; + else if (( file_buf[0] == 'L' ) && ( strstr(file_buf, "LINK=0") == file_buf )) // LINK= + str_ptr += 5; + else if (( file_buf[0] == 'M' ) && ( strstr(file_buf, "MEMBER=0") == file_buf )) // MEMBER= + { + str_ptr += 7; + fSpecial = true; + } + else if (( file_buf[0] == 'M' ) && ( strstr(file_buf, "MORE1=0") == file_buf )) // MORE1= + str_ptr += 6; + else if (( file_buf[0] == 'M' ) && ( strstr(file_buf, "MORE2=0") == file_buf )) // MORE2= + str_ptr += 6; + else if (( file_buf[0] == 'S' ) && ( strstr(file_buf, "SERIAL=0") == file_buf )) // SERIAL= + str_ptr += 7; + else if ((( file_buf[0] == 'T' ) && ( strstr(file_buf, "TAG.") == file_buf )) || // TAG.= + (( file_buf[0] == 'R' ) && ( strstr(file_buf, "REGION.TAG") == file_buf ))) + { + while ( *str_ptr && ( *str_ptr != '=' )) + ++str_ptr; + ++str_ptr; + } + else if (( i == 2 ) && strchr(file_buf, '=')) // spheredata.scp - plain VARs + { + while ( *str_ptr && ( *str_ptr != '=' )) + ++str_ptr; + ++str_ptr; + } + else + str_ptr = nullptr; + + // UIDs are always hex, so prefixed by 0 + if ( str_ptr && ( *str_ptr != '0' )) + str_ptr = nullptr; + + // here we got potentialy UID-contained variable + // check if it really is only UID-like var containing + if ( str_ptr ) + { + str_ptr_2 = str_ptr; + while ( *str_ptr_2 && + ((( *str_ptr_2 >= '0' ) && ( *str_ptr_2 <= '9' )) || + (( *str_ptr_2 >= 'a' ) && ( *str_ptr_2 <= 'f' ))) ) + ++str_ptr_2; + if ( !fSpecial ) + { + if ( *str_ptr_2 && ( *str_ptr_2 != '\r' ) && ( *str_ptr_2 != '\n' )) // some more text in line + str_ptr = nullptr; + } + } + + // here we definitely know that this is very uid-like + if ( str_ptr ) + { + char c, c1, c2; + c = *str_ptr_2; + + *str_ptr_2 = 0; + // here in p we have the current value of the line. + // check if it is a valid UID + + // prepare converting 0.. to 0x.. + c1 = *(str_ptr-1); + c2 = *str_ptr; + *(str_ptr-1) = '0'; + *str_ptr = 'x'; + --str_ptr; + dwIdxUID = strtoul(str_ptr, &str_ptr_2, 16); + ++str_ptr; + *(str_ptr-1) = c1; + *str_ptr = c2; + // Note 28-Jun-2004 + // The search algourytm is very simple and fast. But maybe integrate some other, at least /2 algorythm + // since has amount/2 tryes at worst chance to get the item and never scans the whole array + // It should improve speed since defragmenting 150Mb saves takes ~2:30 on 2.0Mhz CPU + { + dword dStep = dwTotalUIDs /2; + dword d = dStep; + for (;;) + { + dStep /= 2; + + if ( puids[d] == dwIdxUID) + { + dwIdxUID = d | (puids[d]&0xF0000000); // do not forget attach item and special flags like 04.. + break; + } + else + { + if (puids[d] < dwIdxUID) + d += dStep; + else + d -= dStep; + } + + if ( dStep == 1 ) + { + dwIdxUID = 0xFFFFFFFFL; + break; // did not find the UID + } + } + } + + // Search for this uid in the table + /* for ( d = 0; d < dTotalUIDs; d++ ) + { + if ( !uids[d] ) // end of array + { + uid = 0xFFFFFFFFL; + break; + } + else if ( uids[d] == uid ) + { + uid = d | (uids[d]&0xF0000000); // do not forget attach item and special flags like 04.. + break; + } + }*/ + + // replace UID by the new one since it has been found + *str_ptr_2 = c; + if (dwIdxUID != 0xFFFFFFFFL ) + { + *str_ptr = 0; + ASSERT(strlen(str_ptr_2) < sizeof(path_buf)); + Str_CopyLimitNull(path_buf, str_ptr_2, sizeof(path_buf)); // here we don't need anymore the old values of path_buf, so i can reuse it here + snprintf(path_buf_2, sizeof(path_buf_2), "0%" PRIx32, dwIdxUID); + strcat(file_buf, path_buf_2); + strcat(file_buf, path_buf); + } + } + // output the resulting line + ouf.Write(file_buf, (int)strlen(file_buf)); + } + inf.Close(); + ouf.Close(); + } + + free(puids); + g_Log.Event(LOGM_INIT, "Defragmentation complete.\n"); +} + //////////////////////////////////////////////////////////////////////////////////////// // -CServer diff --git a/src/game/CServerDef.cpp b/src/game/CServerDef.cpp index 232c7a691..a60500067 100644 --- a/src/game/CServerDef.cpp +++ b/src/game/CServerDef.cpp @@ -38,7 +38,7 @@ #else // (Unix) #include #endif - bool m_fPmemory = true; // process memory information is available? + static bool sm_fHasMemoryInfo = true; // process memory information is available? ////////////////////////////////////////////////////////////////////// // -CServerDef @@ -68,7 +68,7 @@ size_t CServerDef::StatGet(SERV_STAT_TYPE i) const if ( i == SERV_STAT_MEM ) // memory information { d = 0; - if ( m_fPmemory ) + if ( sm_fHasMemoryInfo ) { #ifdef _WIN32 if ( !m_hmPsapiDll ) // try to load psapi.dll if not loaded yet @@ -147,7 +147,7 @@ size_t CServerDef::StatGet(SERV_STAT_TYPE i) const if ( !d ) { g_Log.EventError(("Unable to load process information from getrusage() and procfs. Memory information will be not available.\n")); - m_fPmemory = false; + sm_fHasMemoryInfo = false; } #endif } diff --git a/src/game/CWorld.cpp b/src/game/CWorld.cpp index 1d09fa9e3..05134381d 100644 --- a/src/game/CWorld.cpp +++ b/src/game/CWorld.cpp @@ -1,15 +1,15 @@ #include "../common/CException.h" #include "../common/CExpression.h" +#include "../common/CLog.h" #include "../common/sphereversion.h" #include "../network/CClientIterator.h" #include "../network/CNetworkManager.h" #include "../sphere/ProfileTask.h" -#include "../common/CLog.h" #include "chars/CChar.h" #include "clients/CClient.h" #include "clients/CGMPage.h" #include "items/CItemMulti.h" -#include "items/CItemStone.h" +#include "items/CItemStone.h" // Needed to use CItemmStone methods, the unique_ptr was forward declared in the header #include "CServer.h" #include "CScriptProfiler.h" #include "CSector.h" @@ -24,7 +24,7 @@ #include -lpctstr GetReasonForGarbageCode(int iCode = -1) +static lpctstr GetReasonForGarbageCode(int iCode = -1) noexcept { lpctstr pStr; switch ( iCode ) @@ -194,7 +194,7 @@ lpctstr GetReasonForGarbageCode(int iCode = -1) return pStr; } -void ReportGarbageCollection(CObjBase * pObj, int iResultCode) +static void ReportGarbageCollection(CObjBase * pObj, int iResultCode) { ASSERT(pObj != nullptr); @@ -967,7 +967,7 @@ bool CWorld::SaveForce() // Save world state else pCurBlock = save_msgs[5]; - fSave = SaveStage(); + fSave = SaveStage(); if ( !(_iSaveStage & 0x7F) ) { g_Serv.PrintPercent( _iSaveStage, (ssize_t)iSectorsQty + 3 ); diff --git a/src/game/chars/CChar.cpp b/src/game/chars/CChar.cpp index cf14716cc..42802a5b6 100644 --- a/src/game/chars/CChar.cpp +++ b/src/game/chars/CChar.cpp @@ -1591,7 +1591,7 @@ void CChar::SetID( CREID_TYPE id ) CCharBase * pCharDef = CCharBase::FindCharBase(id); if ( pCharDef == nullptr ) { - if ( (id != (CREID_TYPE)-1) && (id != CREID_INVALID) ) + if ( id != CREID_INVALID ) DEBUG_ERR(("Setting invalid char ID 0%x\n", id)); id = (CREID_TYPE)(g_Cfg.ResourceGetIndexType(RES_CHARDEF, "DEFAULTCHAR")); @@ -4995,7 +4995,7 @@ bool CChar::OnTriggerSpeech( bool bIsPet, lpctstr pszText, CChar * pSrc, TALKMOD } // Gaining exp -uint Calc_ExpGet_Exp(uint level) +static uint Calc_ExpGet_Exp(uint level) { if (level <= 1) return 0; @@ -5015,7 +5015,7 @@ uint Calc_ExpGet_Exp(uint level) } // Increasing level -uint Calc_ExpGet_Level(uint exp) +static uint Calc_ExpGet_Level(uint exp) { if (g_Cfg.m_iLevelNextAt < 1) //Must do this check in case ini's LevelNextAt is not set or server will freeze because exp will never decrease in the while. { diff --git a/src/game/spheresvr.cpp b/src/game/spheresvr.cpp index 350d633ae..176ce878d 100644 --- a/src/game/spheresvr.cpp +++ b/src/game/spheresvr.cpp @@ -164,9 +164,8 @@ CSStringList g_AutoComplete; // auto-complete list CScriptProfiler g_profiler; // script profiler CUOMapList g_MapList; // global maps information -MainThread g_Main; -extern PingServer g_PingServer; -extern CDataBaseAsyncHelper g_asyncHdb; +static MainThread g_Main; +static PingServer g_PingServer; @@ -469,304 +468,6 @@ static void Sphere_MainMonitorLoop() } -//****************************************************** - -static void dword_q_sort(dword *numbers, dword left, dword right) -{ - dword pivot, l_hold, r_hold; - - l_hold = left; - r_hold = right; - pivot = numbers[left]; - while (left < right) - { - while ((numbers[right] >= pivot) && (left < right)) right--; - if (left != right) - { - numbers[left] = numbers[right]; - left++; - } - while ((numbers[left] <= pivot) && (left < right)) left++; - if (left != right) - { - numbers[right] = numbers[left]; - right--; - } - } - numbers[left] = pivot; - pivot = left; - left = l_hold; - right = r_hold; - if (left < pivot) - dword_q_sort(numbers, left, pivot-1); - if (right > pivot) - dword_q_sort(numbers, pivot+1, right); -} - -void defragSphere(char *path) -{ - ASSERT(path != nullptr); - - constexpr size_t mb10 = 10*1024*1024; - constexpr size_t mb5 = 5*1024*1024; - - CSFileText inf; - CSFile ouf; - char file_buf[1024]; - char path_buf[_MAX_PATH], path_buf_2[_MAX_PATH]; - char *str_ptr = nullptr, *str_ptr_2 = nullptr; - - g_Log.Event(LOGM_INIT, "Defragmentation (UID alteration) of " SPHERE_TITLE " saves.\n" - "Use it on your risk and if you know what you are doing since it can possibly harm your server.\n" - "The process can take up to several hours depending on the CPU you have.\n" - "After finished, you will have your '" SPHERE_FILE "*.scp' files converted and saved as '" SPHERE_FILE "*.scp.new'.\n"); - - // UID_O_INDEX_MASK ? - constexpr dword MAX_UID = 40'000'000U; // limit to 40mln of objects, takes 40mln*4bytes ~= 160mb - - dword dwIdxUID = 0; - dword* puids = (dword*)calloc(MAX_UID, sizeof(dword)); - for ( uint i = 0; i < 3; ++i ) - { - Str_CopyLimitNull(path_buf, path, sizeof(path_buf)); - if ( i == 0 ) strcat(path_buf, SPHERE_FILE "statics" SPHERE_SCRIPT); - else if ( i == 1 ) strcat(path_buf, SPHERE_FILE "world" SPHERE_SCRIPT); - else strcat(path_buf, SPHERE_FILE "chars" SPHERE_SCRIPT); - - g_Log.Event(LOGM_INIT, "Reading current UIDs: %s\n", path_buf); - if ( !inf.Open(path_buf, OF_READ|OF_TEXT|OF_DEFAULTMODE) ) - { - g_Log.Event(LOGM_INIT, "Cannot open file for reading. Skipped!\n"); - continue; - } - size_t uiBytesRead = 0, uiTotalMb = 0; - while ((dwIdxUID < MAX_UID) && !feof(inf._pStream)) - { - fgets(file_buf, sizeof(file_buf), inf._pStream); - uiBytesRead += strlen(file_buf); - if ( uiBytesRead > mb10 ) - { - uiBytesRead -= mb10; - uiTotalMb += 10; - g_Log.Event(LOGM_INIT, "Total read %" PRIuSIZE_T " Mb\n", uiTotalMb); - } - if (( file_buf[0] == 'S' ) && ( strstr(file_buf, "SERIAL=") == file_buf )) - { - str_ptr = file_buf + 7; - str_ptr_2 = str_ptr; - while (*str_ptr_2 && (*str_ptr_2 != '\r') && (*str_ptr_2 != '\n')) - { - ++str_ptr_2; - } - *str_ptr_2 = 0; - - // prepare new uid - *(str_ptr-1) = '0'; - *str_ptr = 'x'; - --str_ptr; - puids[dwIdxUID++] = strtoul(str_ptr, &str_ptr_2, 16); - } - } - inf.Close(); - } - const dword dwTotalUIDs = dwIdxUID; - g_Log.Event(LOGM_INIT, "Totally having %" PRIu32 " unique objects (UIDs), latest: 0%x\n", dwTotalUIDs, puids[dwTotalUIDs-1]); - - g_Log.Event(LOGM_INIT, "Quick-Sorting the UIDs array...\n"); - dword_q_sort(puids, 0, dwTotalUIDs -1); - - for ( uint i = 0; i < 5; ++i ) - { - Str_CopyLimitNull(path_buf, path, sizeof(path_buf)); - if ( !i ) strcat(path_buf, SPHERE_FILE "accu.scp"); - else if ( i == 1 ) strcat(path_buf, SPHERE_FILE "chars" SPHERE_SCRIPT); - else if ( i == 2 ) strcat(path_buf, SPHERE_FILE "data" SPHERE_SCRIPT); - else if ( i == 3 ) strcat(path_buf, SPHERE_FILE "world" SPHERE_SCRIPT); - else if ( i == 4 ) strcat(path_buf, SPHERE_FILE "statics" SPHERE_SCRIPT); - g_Log.Event(LOGM_INIT, "Updating UID-s in %s to %s.new\n", path_buf, path_buf); - if ( !inf.Open(path_buf, OF_READ|OF_TEXT|OF_DEFAULTMODE) ) - { - g_Log.Event(LOGM_INIT, "Cannot open file for reading. Skipped!\n"); - continue; - } - Str_ConcatLimitNull(path_buf, ".new", sizeof(path_buf)); - if ( !ouf.Open(path_buf, OF_WRITE|OF_CREATE|OF_DEFAULTMODE) ) - { - g_Log.Event(LOGM_INIT, "Cannot open file for writing. Skipped!\n"); - continue; - } - - size_t uiBytesRead = 0, uiTotalMb = 0; - while ( inf.ReadString(file_buf, sizeof(file_buf)) ) - { - dwIdxUID = (dword)strlen(file_buf); - if (dwIdxUID > (ARRAY_COUNT(file_buf) - 3)) - dwIdxUID = ARRAY_COUNT(file_buf) - 3; - - file_buf[dwIdxUID] = file_buf[dwIdxUID +1] = file_buf[dwIdxUID +2] = 0; // just to be sure to be in line always - // NOTE: it is much faster than to use memcpy to clear before reading - bool fSpecial = false; - uiBytesRead += dwIdxUID; - if ( uiBytesRead > mb5 ) - { - uiBytesRead -= mb5; - uiTotalMb += 5; - g_Log.Event(LOGM_INIT, "Total processed %" PRIuSIZE_T " Mb\n", uiTotalMb); - } - str_ptr = file_buf; - - // Note 28-Jun-2004 - // mounts seems having ACTARG1 > 0x30000000. The actual UID is ACTARG1-0x30000000. The - // new also should be new+0x30000000. need investigation if this can help making mounts - // not to disappear after the defrag - if (( file_buf[0] == 'A' ) && ( strstr(file_buf, "ACTARG1=0") == file_buf )) // ACTARG1= - str_ptr += 8; - else if (( file_buf[0] == 'C' ) && ( strstr(file_buf, "CONT=0") == file_buf )) // CONT= - str_ptr += 5; - else if (( file_buf[0] == 'C' ) && ( strstr(file_buf, "CHARUID=0") == file_buf )) // CHARUID= - str_ptr += 8; - else if (( file_buf[0] == 'L' ) && ( strstr(file_buf, "LASTCHARUID=0") == file_buf )) // LASTCHARUID= - str_ptr += 12; - else if (( file_buf[0] == 'L' ) && ( strstr(file_buf, "LINK=0") == file_buf )) // LINK= - str_ptr += 5; - else if (( file_buf[0] == 'M' ) && ( strstr(file_buf, "MEMBER=0") == file_buf )) // MEMBER= - { - str_ptr += 7; - fSpecial = true; - } - else if (( file_buf[0] == 'M' ) && ( strstr(file_buf, "MORE1=0") == file_buf )) // MORE1= - str_ptr += 6; - else if (( file_buf[0] == 'M' ) && ( strstr(file_buf, "MORE2=0") == file_buf )) // MORE2= - str_ptr += 6; - else if (( file_buf[0] == 'S' ) && ( strstr(file_buf, "SERIAL=0") == file_buf )) // SERIAL= - str_ptr += 7; - else if ((( file_buf[0] == 'T' ) && ( strstr(file_buf, "TAG.") == file_buf )) || // TAG.= - (( file_buf[0] == 'R' ) && ( strstr(file_buf, "REGION.TAG") == file_buf ))) - { - while ( *str_ptr && ( *str_ptr != '=' )) - ++str_ptr; - ++str_ptr; - } - else if (( i == 2 ) && strchr(file_buf, '=')) // spheredata.scp - plain VARs - { - while ( *str_ptr && ( *str_ptr != '=' )) - ++str_ptr; - ++str_ptr; - } - else - str_ptr = nullptr; - - // UIDs are always hex, so prefixed by 0 - if ( str_ptr && ( *str_ptr != '0' )) - str_ptr = nullptr; - - // here we got potentialy UID-contained variable - // check if it really is only UID-like var containing - if ( str_ptr ) - { - str_ptr_2 = str_ptr; - while ( *str_ptr_2 && - ((( *str_ptr_2 >= '0' ) && ( *str_ptr_2 <= '9' )) || - (( *str_ptr_2 >= 'a' ) && ( *str_ptr_2 <= 'f' ))) ) - ++str_ptr_2; - if ( !fSpecial ) - { - if ( *str_ptr_2 && ( *str_ptr_2 != '\r' ) && ( *str_ptr_2 != '\n' )) // some more text in line - str_ptr = nullptr; - } - } - - // here we definitely know that this is very uid-like - if ( str_ptr ) - { - char c, c1, c2; - c = *str_ptr_2; - - *str_ptr_2 = 0; - // here in p we have the current value of the line. - // check if it is a valid UID - - // prepare converting 0.. to 0x.. - c1 = *(str_ptr-1); - c2 = *str_ptr; - *(str_ptr-1) = '0'; - *str_ptr = 'x'; - --str_ptr; - dwIdxUID = strtoul(str_ptr, &str_ptr_2, 16); - ++str_ptr; - *(str_ptr-1) = c1; - *str_ptr = c2; - // Note 28-Jun-2004 - // The search algourytm is very simple and fast. But maybe integrate some other, at least /2 algorythm - // since has amount/2 tryes at worst chance to get the item and never scans the whole array - // It should improve speed since defragmenting 150Mb saves takes ~2:30 on 2.0Mhz CPU - { - dword dStep = dwTotalUIDs /2; - dword d = dStep; - for (;;) - { - dStep /= 2; - - if ( puids[d] == dwIdxUID) - { - dwIdxUID = d | (puids[d]&0xF0000000); // do not forget attach item and special flags like 04.. - break; - } - else - { - if (puids[d] < dwIdxUID) - d += dStep; - else - d -= dStep; - } - - if ( dStep == 1 ) - { - dwIdxUID = 0xFFFFFFFFL; - break; // did not find the UID - } - } - } - - // Search for this uid in the table -/* for ( d = 0; d < dTotalUIDs; d++ ) - { - if ( !uids[d] ) // end of array - { - uid = 0xFFFFFFFFL; - break; - } - else if ( uids[d] == uid ) - { - uid = d | (uids[d]&0xF0000000); // do not forget attach item and special flags like 04.. - break; - } - }*/ - - // replace UID by the new one since it has been found - *str_ptr_2 = c; - if (dwIdxUID != 0xFFFFFFFFL ) - { - *str_ptr = 0; - ASSERT(strlen(str_ptr_2) < sizeof(path_buf)); - Str_CopyLimitNull(path_buf, str_ptr_2, sizeof(path_buf)); // here we don't need anymore the old values of path_buf, so i can reuse it here - snprintf(path_buf_2, sizeof(path_buf_2), "0%" PRIx32, dwIdxUID); - strcat(file_buf, path_buf_2); - strcat(file_buf, path_buf); - } - } - // output the resulting line - ouf.Write(file_buf, (int)strlen(file_buf)); - } - inf.Close(); - ouf.Close(); - } - - free(puids); - g_Log.Event(LOGM_INIT, "Defragmentation complete.\n"); -} - - void atexit_handler() { ThreadHolder::get().markThreadsClosing(); diff --git a/src/game/triggers.cpp b/src/game/triggers.cpp index ffa50a500..8dd92fbcf 100644 --- a/src/game/triggers.cpp +++ b/src/game/triggers.cpp @@ -21,7 +21,7 @@ struct TRIGGER_T_ID //{ // int m_used; //}; -std::vector g_triggers_id; +static std::vector sm_vTriggersId; bool IsTrigUsed(E_TRIGGERS id) @@ -29,7 +29,7 @@ bool IsTrigUsed(E_TRIGGERS id) if ( g_Serv.IsLoading() == true) return false; - return (( (uint)id < g_triggers_id.size() ) && g_triggers_id[id].m_used ); + return (( (uint)id < sm_vTriggersId.size() ) && sm_vTriggersId[id].m_used ); } bool IsTrigUsed(const char *name) @@ -47,12 +47,12 @@ bool IsTrigUsed(const char *name) void TriglistInit() { TRIGGER_T_ID trig{}; - g_triggers_id.clear(); + sm_vTriggersId.clear(); #define ADD(_a_) \ snprintf(trig.m_name, TRIGGER_NAME_MAX_LEN, "@%s", #_a_); \ trig.m_used = 0; \ - g_triggers_id.push_back(trig); + sm_vTriggersId.push_back(trig); #include "../tables/triggers.tbl" #undef ADD @@ -60,7 +60,7 @@ void TriglistInit() void TriglistClear() { - for ( auto it = g_triggers_id.begin(), end = g_triggers_id.end(); it != end; ++it ) + for ( auto it = sm_vTriggersId.begin(), end = sm_vTriggersId.end(); it != end; ++it ) { it->m_used = 0; } @@ -68,13 +68,13 @@ void TriglistClear() void TriglistAdd(E_TRIGGERS id) { - if (g_triggers_id.size() ) - ++ g_triggers_id[id].m_used; + if (sm_vTriggersId.size() ) + ++ sm_vTriggersId[id].m_used; } void TriglistAdd(const char *name) { - for ( auto it = g_triggers_id.begin(), end = g_triggers_id.end(); it != end; ++it ) + for ( auto it = sm_vTriggersId.begin(), end = sm_vTriggersId.end(); it != end; ++it ) { if ( !strcmpi(it->m_name, name) ) { @@ -87,7 +87,7 @@ void TriglistAdd(const char *name) void Triglist(int &total, int &used) { total = used = 0; - for ( auto it = g_triggers_id.cbegin(), end = g_triggers_id.cend(); it != end; ++it ) + for ( auto it = sm_vTriggersId.cbegin(), end = sm_vTriggersId.cend(); it != end; ++it ) { ++total; if ( it->m_used ) @@ -97,7 +97,7 @@ void Triglist(int &total, int &used) void TriglistPrint() { - for ( auto it = g_triggers_id.cbegin(), end = g_triggers_id.cend(); it != end; ++it ) + for ( auto it = sm_vTriggersId.cbegin(), end = sm_vTriggersId.cend(); it != end; ++it ) { if (it->m_used) { diff --git a/src/network/PingServer.cpp b/src/network/PingServer.cpp index 63a4dd4ad..0c2c3ec50 100644 --- a/src/network/PingServer.cpp +++ b/src/network/PingServer.cpp @@ -3,7 +3,7 @@ #include "PingServer.h" -PingServer g_PingServer; +static PingServer s_PingServer; // run the thread in RealTime as we need pings to be responded to ASAP PingServer::PingServer() : AbstractSphereThread("PingServer", IThread::RealTime) diff --git a/src/network/PingServer.h b/src/network/PingServer.h index 9be1d819a..6e28717ac 100644 --- a/src/network/PingServer.h +++ b/src/network/PingServer.h @@ -23,9 +23,8 @@ class PingServer : public AbstractSphereThread PingServer(void); virtual ~PingServer(void); -private: - PingServer(const PingServer& copy); - PingServer& operator=(const PingServer& other); + PingServer(const PingServer& copy) = delete; + PingServer& operator=(const PingServer& other) = delete; public: virtual void onStart() override; diff --git a/src/sphere/asyncdb.h b/src/sphere/asyncdb.h index aede0ba29..2bc3018c0 100644 --- a/src/sphere/asyncdb.h +++ b/src/sphere/asyncdb.h @@ -39,4 +39,7 @@ class CDataBaseAsyncHelper : public AbstractSphereThread void addQuery(bool isQuery, lpctstr sFunction, lpctstr sQuery); }; +extern CDataBaseAsyncHelper g_asyncHdb; + + #endif // _INC_ASYNCDB_H diff --git a/src/sphere/threads.cpp b/src/sphere/threads.cpp index 5a319fdf9..d68907d97 100644 --- a/src/sphere/threads.cpp +++ b/src/sphere/threads.cpp @@ -803,6 +803,7 @@ char *AbstractSphereThread::allocateBuffer() noexcept return buffer; } +static TemporaryStringThreadSafeStateHolder::TemporaryStringStorage * getThreadRawStringBuffer() { From 250cae76f0b5775065b97470e237b3da303e2a86 Mon Sep 17 00:00:00 2001 From: cbnolok Date: Mon, 23 Sep 2024 19:32:18 +0200 Subject: [PATCH 10/32] Moved all the compiler/linker flags selection for GCC/Clang in CompilerFlagsChecker.cmake. --- .clangd | 3 + CMakeLists.txt | 32 +++- cmake/CompilerFlagsChecker.cmake | 179 +++++++++++++----- .../include/Linux-Clang_common.inc.cmake | 158 ++-------------- .../include/Linux-GNU_common.inc.cmake | 148 ++------------- .../include/OSX-AppleClang_common.inc.cmake | 122 ++---------- .../include/Windows-Clang_common.inc.cmake | 121 +----------- .../include/Windows-GNU_common.inc.cmake | 130 +------------ src/common/CExpression.cpp | 28 +-- src/common/resource/sections/CDialogDef.cpp | 26 +-- src/game/chars/CCharUse.cpp | 4 +- src/game/components/CCSpawn.cpp | 20 +- 12 files changed, 265 insertions(+), 706 deletions(-) diff --git a/.clangd b/.clangd index 6b5f08c53..243a3c7f2 100644 --- a/.clangd +++ b/.clangd @@ -1,5 +1,6 @@ CompileFlags: Add: + # Exclude the following folders from the source code analysis. - -I!.codelite - -I!.ctagsd - -I!.git @@ -15,3 +16,5 @@ CompileFlags: # PathMatch: '.*/src/common/common\.h' # Diagnostics: # Suppress: ['-Wunused-include-directive'] + +# TODO: disable clazy-non-pod-global-static diff --git a/CMakeLists.txt b/CMakeLists.txt index 29766560a..295f32bd4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -35,7 +35,13 @@ option(USE_UBSAN "Enable Undefined Behavior Sanitizer." FALSE) option(USE_LSAN "Enable LeakSanitizer." FALSE) option(USE_MSAN "Enable MemorySanitizer." FALSE) +set(ENABLED_SANITIZER FALSE) +if(USE_ASAN OR USE_MSAN OR USE_LSAN OR USE_MSAN) + set(ENABLED_SANITIZER TRUE) +endif() + # -------------------- Utility functions -------------------- + function(booleanize_str_find VAR) if(${VAR} EQUAL -1) unset(${VAR} PARENT_SCOPE) @@ -75,7 +81,8 @@ set(CMAKE_CXX_EXTENSIONS OFF) set(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "") set(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "") -# CMake also sets other predefined flags, which we don't want... +# CMake also sets other predefined flags, which we don't want? +#[[ set(CMAKE_C_FLAGS "") set(CMAKE_C_FLAGS_DEBUG "") set(CMAKE_C_FLAGS_NIGHTLY "") @@ -90,6 +97,7 @@ set(CMAKE_EXE_LINKER_FLAGS "") set(CMAKE_EXE_LINKER_FLAGS_DEBUG "") set(CMAKE_EXE_LINKER_FLAGS_NIGHTLY "") set(CMAKE_EXE_LINKER_FLAGS_RELEASE "") +]] set(is_win32_app_linker) if(WIN32 AND NOT ${WIN32_SPAWN_CONSOLE}) @@ -213,8 +221,26 @@ endif(SINGLE_TARGET) # -------------------- -#message(STATUS) -#include("${CMAKE_SOURCE_DIR}/cmake/CompilerFlagsChecker.cmake") +message(STATUS) +include("${CMAKE_SOURCE_DIR}/cmake/CompilerFlagsChecker.cmake") + +# -------------------- + +if(USE_ASAN) + set(PREPROCESSOR_DEFS_EXTRA ${PREPROCESSOR_DEFS_EXTRA} ADDRESS_SANITIZER) +endif() +if(USE_UBSAN) + set(PREPROCESSOR_DEFS_EXTRA ${PREPROCESSOR_DEFS_EXTRA} UNDEFINED_BEHAVIOR_SANITIZER) +endif() +if(USE_LSAN) + set(PREPROCESSOR_DEFS_EXTRA ${PREPROCESSOR_DEFS_EXTRA} LEAK_SANITIZER) +endif() +if(USE_MSAN) + set(PREPROCESSOR_DEFS_EXTRA ${PREPROCESSOR_DEFS_EXTRA} MEMORY_SANITIZER) +endif() +if(ENABLED_SANITIZER) + set(PREPROCESSOR_DEFS_EXTRA ${PREPROCESSOR_DEFS_EXTRA} _SANITIZERS) +endif() # -------------------- diff --git a/cmake/CompilerFlagsChecker.cmake b/cmake/CompilerFlagsChecker.cmake index 6826f0cac..039af7d1e 100644 --- a/cmake/CompilerFlagsChecker.cmake +++ b/cmake/CompilerFlagsChecker.cmake @@ -3,6 +3,19 @@ message(STATUS "Checking available compiler flags...") if(NOT MSVC) message(STATUS "-- Compilation options:") + + # Compiler option flags. + list( + APPEND + compiler_options_base + -pthread + -fexceptions + -fnon-call-exceptions + -pipe + -ffast-math + ) + list(APPEND compiler_options_warning_base -Werror;-Wall;-Wextra;-Wpedantic) + # Compiler option flags. Common to both compilers, but older versions might not support the following. #check_cxx_compiler_flag("" COMP_HAS_) @@ -10,13 +23,17 @@ if(NOT MSVC) check_cxx_compiler_flag("-fno-expensive-optimizations" COMP_HAS_FNO_EXPENSIVE_OPTIMIZATIONS) # Compiler option flags. Expected to work on Clang but not GCC, at the moment. - #check_cxx_compiler_flag("-fforce-emit-vtables" COMP_HAS_F_FORCE_EMIT_VTABLES) + # check_cxx_compiler_flag("-fforce-emit-vtables" COMP_HAS_F_FORCE_EMIT_VTABLES) + # -fwhole-program-vtables + # -fstrict-vtable-pointers if(${USE_ASAN}) # Compiler option flags. Sanitizers related (ASAN). message(STATUS "-- Compilation options (Address Sanitizer):") + set(CMAKE_REQUIRED_LIBRARIES -fsanitize=address) # link against sanitizer lib, being required by the following compilation test check_cxx_compiler_flag("-fsanitize=address" COMP_HAS_ASAN) + unset(CMAKE_REQUIRED_LIBRARIES) if(NOT COMP_HAS_ASAN) message(FATAL_ERROR "This compiler does not support Address Sanitizer. Disable it.") endif() @@ -32,7 +49,9 @@ if(NOT MSVC) # Compiler option flags. Sanitizers related (UBSAN). message(STATUS "-- Compilation options (Undefined Behavior Sanitizer):") + set(CMAKE_REQUIRED_LIBRARIES -fsanitize=undefined) # link against sanitizer lib, being required by the following compilation test check_cxx_compiler_flag("-fsanitize=undefined" COMP_HAS_UBSAN) + unset(CMAKE_REQUIRED_LIBRARIES) if(NOT COMP_HAS_UBSAN) message(FATAL_ERROR "This compiler does not support Undefined Behavior Sanitizer. Disable it.") endif() @@ -48,7 +67,9 @@ if(NOT MSVC) # Compiler option flags. Sanitizers related (LSAN). message(STATUS "-- Compilation options (Leak Sanitizer):") + set(CMAKE_REQUIRED_LIBRARIES -fsanitize=leak) # link against sanitizer lib, being required by the following compilation test check_cxx_compiler_flag("-fsanitize=leak" COMP_HAS_LSAN) + unset(CMAKE_REQUIRED_LIBRARIES) if(NOT COMP_HAS_LSAN) message(FATAL_ERROR "This compiler does not support Leak Sanitizer. Disable it.") endif() @@ -56,13 +77,30 @@ if(NOT MSVC) if(${USE_MSAN}) # Compiler option flags. Sanitizers related (UBSAN). - message(STATUS "-- Compilation options (Memory Behavior Sanitizer):") + + set(CMAKE_REQUIRED_LIBRARIES -fsanitize=memory) # link against sanitizer lib, being required by the following compilation test check_cxx_compiler_flag("-fsanitize=memory" COMP_HAS_MSAN) + unset(CMAKE_REQUIRED_LIBRARIES) if(NOT COMP_HAS_MSAN) message(FATAL_ERROR "This compiler does not support Memory Sanitizer. Disable it.") endif() + # MemorySanitizer: it doesn't work out of the box. It needs to be linked to an MSAN-instrumented build of libc++ and libc++abi. + # This means: one should build them from LLVM source... + # https://github.com/google/sanitizers/wiki/MemorySanitizerLibcxxHowTo + #IF (${USE_MSAN}) + # SET (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++") + #ENDIF() + # Use "-stdlib=libstdc++" to link against GCC c/c++ libs (this is done by default) + # To use LLVM libc++ use "-stdlib=libc++", but you need to install it separately + + message( + WARNING + "You have enabled MSAN. Make sure you do know what you are doing. It doesn't work out of the box. \ +See comments in the toolchain and: https://github.com/google/sanitizers/wiki/MemorySanitizerLibcxxHowTo" + ) + check_cxx_compiler_flag("-fsanitize=memory-track-origins" COMP_HAS_F_SANITIZE_MEMORY_TRACK_ORIGINS) check_cxx_compiler_flag("-fPIE" COMP_HAS_F_PIE) endif() @@ -88,10 +126,10 @@ if(NOT MSVC) # Compiler warning flags. message(STATUS "-- Compilation options (warnings):") - check_cxx_compiler_flag("-Wuseless-cast" COMP_HAS_W_USELESS_CAST) + #check_cxx_compiler_flag("-Wuseless-cast" COMP_HAS_W_USELESS_CAST) check_cxx_compiler_flag("-Wnull-dereference" COMP_HAS_W_NULL_DEREFERENCE) - check_cxx_compiler_flag("-Wconversion" COMP_HAS_W_CONVERSION) # Temporarily disabled. Implicit type conversions that might change a value, such as narrowing conversions. - check_cxx_compiler_flag("-Wcast-qual" COMP_HAS_W_CAST_QUAL) # casts that remove a type's const or volatile qualifier. + #check_cxx_compiler_flag("-Wconversion" COMP_HAS_W_CONVERSION) # Temporarily disabled. Implicit type conversions that might change a value, such as narrowing conversions. + #check_cxx_compiler_flag("-Wcast-qual" COMP_HAS_W_CAST_QUAL) # casts that remove a type's const or volatile qualifier. check_cxx_compiler_flag("-Wzero-as-null-pointer-constant" COMP_HAS_W_ZERO_NULLPTR) check_cxx_compiler_flag("-Wdisabled-optimization" COMP_HAS_W_DISABLE_OPT) check_cxx_compiler_flag("-Winvalid-pch" COMP_HAS_W_INVALID_PCH) @@ -121,18 +159,19 @@ if(NOT MSVC) # Compiler warning flags. To be disabled. message(STATUS "-- Compilation options (disable specific warnings):") - check_cxx_compiler_flag("-Wno-format-nonliteral" COMP_HAS_WNO_FORMAT_NONLITERAL) # Since -Wformat=2 is stricter, you would need to disable this warning. - check_cxx_compiler_flag("-Wno-nonnull-compare" COMP_HAS_WNO_NONNULL_COMPARE) - check_cxx_compiler_flag("-Wno-maybe-uninitialized" COMP_HAS_WNO_MAYBE_UNINIT) - check_cxx_compiler_flag("-Wno-switch" COMP_HAS_WNO_SWITCH) - check_cxx_compiler_flag("-Wno-implicit-fallthrough" COMP_HAS_WNO_IMPLICIT_FALLTHROUGH) - check_cxx_compiler_flag("-Wno-parentheses" COMP_HAS_WNO_PARENTHESES) - check_cxx_compiler_flag("-Wno-misleading-indentation" COMP_HAS_WNO_MISLEADING_INDENTATION) - check_cxx_compiler_flag("-Wno-unused-result" COMP_HAS_WNO_UNUSED_RESULT) - check_cxx_compiler_flag("-Wno-nested-anon-types" COMP_HAS_WNO_NESTED_ANON_TYPES) - check_cxx_compiler_flag("-Wno-format-security" COMP_HAS_WNO_FORMAT_SECURITY) # TODO: remove that when we'll have time to fix every printf format issue - check_cxx_compiler_flag("-Wno-deprecated-declarations" COMP_HAS_WNO_DEPRECATED_DECLARATIONS) - #check_cxx_compiler_flag("-Wno-unknown-pragmas" COMP_HAS_) + check_cxx_compiler_flag("-Wunused-function" COMP_HAS_WNO_UNUSED_FUNCTION) + check_cxx_compiler_flag("-Wformat-nonliteral" COMP_HAS_WNO_FORMAT_NONLITERAL) # Since -Wformat=2 is stricter, you would need to disable this warning. + check_cxx_compiler_flag("-Wnonnull-compare" COMP_HAS_WNO_NONNULL_COMPARE) + check_cxx_compiler_flag("-Wmaybe-uninitialized" COMP_HAS_WNO_MAYBE_UNINIT) + check_cxx_compiler_flag("-Wswitch" COMP_HAS_WNO_SWITCH) + check_cxx_compiler_flag("-Wimplicit-fallthrough" COMP_HAS_WNO_IMPLICIT_FALLTHROUGH) + check_cxx_compiler_flag("-Wparentheses" COMP_HAS_WNO_PARENTHESES) + check_cxx_compiler_flag("-Wmisleading-indentation" COMP_HAS_WNO_MISLEADING_INDENTATION) + check_cxx_compiler_flag("-Wunused-result" COMP_HAS_WNO_UNUSED_RESULT) + check_cxx_compiler_flag("-Wnested-anon-types" COMP_HAS_WNO_NESTED_ANON_TYPES) + check_cxx_compiler_flag("-Wformat-security" COMP_HAS_WNO_FORMAT_SECURITY) # TODO: remove that when we'll have time to fix every printf format issue + check_cxx_compiler_flag("-Wdeprecated-declarations" COMP_HAS_WNO_DEPRECATED_DECLARATIONS) + #check_cxx_compiler_flag("-Wunknown-pragmas" COMP_HAS_) #check_cxx_compiler_flag("" COMP_HAS_) else(NOT MSVC) # Compiler warning flags (MSVC). @@ -151,6 +190,10 @@ endif() if(COMP_HAS_ASAN) list(APPEND checked_compiler_options_asan "-fsanitize=address") + list(APPEND checked_linker_options_all "-fsanitize=address") + if(RUNTIME_STATIC_LINK) + list(APPEND checked_linker_options_all "-static-libasan") + endif() if(COMP_HAS_FSAN_CFI) list(APPEND checked_compiler_options_asan "-fsanitize-cfi") endif() @@ -170,6 +213,10 @@ endif() if(COMP_HAS_UBSAN) list(APPEND checked_compiler_options_ubsan "-fsanitize=undefined") + list(APPEND checked_linker_options_all "-fsanitize=undefined") + if(RUNTIME_STATIC_LINK) + list(APPEND checked_linker_options_all "-static-libubsan") + endif() if(COMP_HAS_FSAN_FLOAT_DIVIDE_BY_ZERO) list(APPEND checked_compiler_options_ubsan "-fsanitize=float-divide-by-zero") endif() @@ -189,15 +236,24 @@ endif() if(COMP_HAS_LSAN) list(APPEND checked_compiler_options_lsan "-fsanitize=leak") + list(APPEND checked_linker_options_all "-fsanitize=leak") + if(RUNTIME_STATIC_LINK) + list(APPEND checked_linker_options_all "-static-liblsan") + endif() endif() if(COMP_HAS_MSAN) list(APPEND checked_compiler_options_msan "-fsanitize=memory") + list(APPEND checked_linker_options_all "-fsanitize=memory") + if(RUNTIME_STATIC_LINK) + list(APPEND checked_linker_options_all "-static-libmsan") + endif() if(COMP_HAS_F_SANITIZE_MEMORY_TRACK_ORIGINS) list(APPEND checked_compiler_options_msan "-fsanitize=memory-track-origins") endif() if(COMP_HAS_F_PIE) list(APPEND checked_compiler_options_msan "-fPIE") + list(APPEND checked_linker_options_all "-pie") endif() endif() @@ -283,6 +339,9 @@ if(COMP_HAS_W_MISSING_VARIABLE_DECL) list(APPEND checked_compiler_warnings "-Wmissing-variable-declarations") endif() +if(COMP_HAS_WNO_UNUSED_FUNCTION) + list(APPEND checked_compiler_warnings_disabled "-Wno-unused-function") +endif() if(COMP_HAS_WNO_FORMAT_NONLITERAL) list(APPEND checked_compiler_warnings_disabled "-Wno-format-nonliteral") endif() @@ -320,7 +379,7 @@ endif() # ---- MSVC if(COMP_HAS_DEFINE_MACRO_EXPANSION) - list(APPEND checked_compiler_flags_msvc "/Wd5105") + list(APPEND checked_compiler_options_msvc "/Wd5105") endif() # ---- Double checks @@ -344,34 +403,68 @@ set(checked_compiler_options_asan) set(checked_compiler_options_sanitize_harden) set(checked_compiler_warnings) set(checked_compiler_warnings_disabled) -set(checked_compiler_flags_msvc) +set(checked_compiler_options_msvc) ]] -message(STATUS "Adding the following conditional compiler options: ${checked_compiler_options}.") -if(COMP_HAS_ASAN) - message(STATUS "Adding the following conditional compiler options for ASan: ${checked_compiler_options_asan}.") -endif() -if(COMP_HAS_UBSAN) - message(STATUS "Adding the following conditional compiler options for UBSan: ${checked_compiler_options_ubsan}.") -endif() -if(COMP_HAS_LSAN) - message(STATUS "Adding the following conditional compiler options for LSan: ${checked_compiler_options_lsan}.") -endif() +## ---- + +list( + APPEND + list_gnu_explicit_compiler_options_all + ${compiler_options_base} + ${compiler_options_warning_base} + ${checked_compiler_options} + ${checked_compiler_options_asan} + ${checked_compiler_options_ubsan} + ${checked_compiler_options_lsan} + ${checked_compiler_options_msan} + ${checked_compiler_options_sanitize_harden} + ${checked_compiler_warnings} + ${checked_compiler_warnings_disabled} + ${checked_compiler_options_msvc} +) -if(COMP_HAS_MSAN) - message(STATUS "Adding the following conditional compiler options for MSan: ${checked_compiler_options_msan}.") -endif() +list(APPEND list_gnu_explicit_linker_options_all ${checked_linker_options_all};-pthread;-dynamic;-Wl,--fatal-warnings) -message( - STATUS - "Adding the following conditional compiler options for hardening: ${checked_compiler_options_sanitize_harden}." -) -message(STATUS "Adding the following conditional compiler warnings: ${checked_compiler_warnings}.") -message( - STATUS - "Adding the following conditional compiler warnings ignore options: ${checked_compiler_warnings_disabled}." -) +#string(JOIN " " string_checked_compiler_options_all ${list_checked_compiler_options_all}) +#set(string_checked_compiler_options_all CACHE STRING "Additional compiler flags, dynamically added." FORCE) +set(list_gnu_explicit_compiler_options_all CACHE STRING "Additional compiler flags, dynamically added." FORCE) +set(list_gnu_explicit_linker_options_all CACHE STRING "Additional linker flags, dynamically added." FORCE) + +## ---- + +if(NOT MSVC) + message(STATUS "Adding the following base compiler options: ${compiler_options_base}") + message(STATUS "Adding the following base compiler warning options: ${compiler_options_warning_base}") + + message(STATUS "Adding the following conditional compiler options: ${checked_compiler_options}.") + if(COMP_HAS_ASAN) + message(STATUS "Adding the following conditional compiler options for ASan: ${checked_compiler_options_asan}.") + endif() + if(COMP_HAS_UBSAN) + message( + STATUS + "Adding the following conditional compiler options for UBSan: ${checked_compiler_options_ubsan}." + ) + endif() + if(COMP_HAS_LSAN) + message(STATUS "Adding the following conditional compiler options for LSan: ${checked_compiler_options_lsan}.") + endif() + + if(COMP_HAS_MSAN) + message(STATUS "Adding the following conditional compiler options for MSan: ${checked_compiler_options_msan}.") + endif() -if(MSVC) - message(STATUS "Adding the following conditional compiler options: ${checked_compiler_flags_msvc}.") + message( + STATUS + "Adding the following conditional compiler options for hardening: ${checked_compiler_options_sanitize_harden}." + ) + message(STATUS "Adding the following conditional compiler warnings: ${checked_compiler_warnings}.") + message( + STATUS + "Adding the following conditional compiler warnings ignore options: ${checked_compiler_warnings_disabled}." + ) + message(STATUS "Adding the following linker options: ${list_gnu_explicit_linker_options_all}.") +elseif(MSVC) + message(STATUS "Adding the following conditional compiler options: ${checked_compiler_options_msvc}.") endif() diff --git a/cmake/toolchains/include/Linux-Clang_common.inc.cmake b/cmake/toolchains/include/Linux-Clang_common.inc.cmake index 88695e547..b7493dc50 100644 --- a/cmake/toolchains/include/Linux-Clang_common.inc.cmake +++ b/cmake/toolchains/include/Linux-Clang_common.inc.cmake @@ -9,186 +9,54 @@ function(toolchain_exe_stuff_common) message(STATUS "Locating libraries to be linked to...") - set(LIBS_LINK_LIST mariadb dl) - foreach(LIB_NAME ${LIBS_LINK_LIST}) - find_library(LIB_${LIB_NAME}_WITH_PATH ${LIB_NAME} PATH ${lib_search_paths}) - message(STATUS "Library ${LIB_NAME}: ${LIB_${LIB_NAME}_WITH_PATH}") + set(libs_link_list mariadb dl) + foreach(lib_name ${libs_link_list}) + find_library(lib_${lib_name}_with_path ${lib_name} PATH ${lib_search_paths}) + message(STATUS "Library ${lib_name}: ${lib_${lib_name}_with_path}") endforeach() #-- Validate sanitizers options and store them between the common compiler flags. - set(ENABLED_SANITIZER false) # From https://clang.llvm.org/docs/ClangCommandLineReference.html # -static-libsan Statically link the sanitizer runtime (Not supported for ASan, TSan or UBSan on darwin) #string(REPLACE ";" " " CXX_FLAGS_EXTRA "${CXX_FLAGS_EXTRA}") - if(${USE_ASAN}) - set(CXX_FLAGS_EXTRA - ${CXX_FLAGS_EXTRA} - # -fsanitize=safe-stack # Can't be used with asan! - -fsanitize=address - -fno-sanitize-recover=address - #-fsanitize-cfi # cfi: control flow integrity - -fsanitize-address-use-after-scope - -fsanitize=pointer-compare - -fsanitize=pointer-subtract - # Flags for additional instrumentation not strictly needing asan to be enabled - -fcf-protection=full - -fstack-check - -fstack-protector-all - -fstack-clash-protection - # Not supported by Clang, but supported by GCC - #-fvtable-verify=preinit -fharden-control-flow-redundancy -fhardcfr-check-exceptions - # Other - #-fsanitize-trap=all - ) - set(CMAKE_EXE_LINKER_FLAGS_EXTRA ${CMAKE_EXE_LINKER_FLAGS_EXTRA} -fsanitize=address) - set(PREPROCESSOR_DEFS_EXTRA ${PREPROCESSOR_DEFS_EXTRA} ADDRESS_SANITIZER) - set(ENABLED_SANITIZER true) - endif() - if(${USE_MSAN}) - message( - WARNING - "You have enabled MSAN. Make sure you do know what you are doing. It doesn't work out of the box. \ -See comments in the toolchain and: https://github.com/google/sanitizers/wiki/MemorySanitizerLibcxxHowTo" - ) - set(CXX_FLAGS_EXTRA ${CXX_FLAGS_EXTRA} -fsanitize=memory -fsanitize-memory-track-origins -fPIE) - set(CMAKE_EXE_LINKER_FLAGS_EXTRA ${CMAKE_EXE_LINKER_FLAGS_EXTRA} -fsanitize=memory) - set(PREPROCESSOR_DEFS_EXTRA ${PREPROCESSOR_DEFS_EXTRA} MEMORY_SANITIZER) - set(ENABLED_SANITIZER true) - endif() - if(${USE_LSAN}) - set(CXX_FLAGS_EXTRA ${CXX_FLAGS_EXTRA} -fsanitize=leak) - set(CMAKE_EXE_LINKER_FLAGS_EXTRA ${CMAKE_EXE_LINKER_FLAGS_EXTRA} -fsanitize=leak>) - set(PREPROCESSOR_DEFS_EXTRA ${PREPROCESSOR_DEFS_EXTRA} LEAK_SANITIZER) - set(ENABLED_SANITIZER true) - endif() - if(${USE_UBSAN}) - set(UBSAN_FLAGS - -fsanitize=undefined,float-divide-by-zero,local-bounds - -fno-sanitize=enum - # Supported? - -fsanitize=unsigned-integer-overflow #Unlike signed integer overflow, this is not undefined behavior, but it is often unintentional. - -fsanitize=implicit-conversion - ) - set(CXX_FLAGS_EXTRA ${CXX_FLAGS_EXTRA} ${UBSAN_FLAGS} -fsanitize=return,vptr) - set(CMAKE_EXE_LINKER_FLAGS_EXTRA ${CMAKE_EXE_LINKER_FLAGS_EXTRA} -fsanitize=undefined) - set(PREPROCESSOR_DEFS_EXTRA ${PREPROCESSOR_DEFS_EXTRA} UNDEFINED_BEHAVIOR_SANITIZER) - set(ENABLED_SANITIZER true) - endif() - - if(${ENABLED_SANITIZER}) - set(PREPROCESSOR_DEFS_EXTRA ${PREPROCESSOR_DEFS_EXTRA} _SANITIZERS) - set(CMAKE_EXE_LINKER_FLAGS_EXTRA - ${CMAKE_EXE_LINKER_FLAGS_EXTRA} - $<$:-static-libsan> - ) - endif() - - #-- Store compiler flags common to all builds. - - set(cxx_local_opts_warnings - -Werror - -Wall - -Wextra - -Wpedantic - - -Wmissing-include-dirs # Warns when an include directory provided with -I does not exist. - -Wformat=2 - #-Wcast-qual # Warns about casts that remove a type's const or volatile qualifier. - #-Wconversion # Temporarily disabled. Warns about implicit type conversions that might change a value, such as narrowing conversions. - -Wdisabled-optimization - #-Winvalid-pch - -Wzero-as-null-pointer-constant - -Wnull-dereference - - # Clang-only - -Wweak-vtables - #-Wmissing-prototypes - #-Wmissing-variable-declarations - - # Unsupported by Clang, but supported by GCC: - #-fno-expensive-optimizations - #-Wtrampolines # Warns when trampolines (a technique to implement nested functions) are generated (don't want this for security reasons). - #-Wvector-operation-performance - #-Wsized-deallocation - #-Wduplicated-cond - #-Wshift-overflow=2 - #-Wno-maybe-uninitialized - #-Wno-nonnull-compare - - # Disable errors: - -Wno-format-nonliteral # Since -Wformat=2 is stricter, you would need to disable this warning. - -Wno-switch - -Wno-implicit-fallthrough - -Wno-parentheses - -Wno-misleading-indentation - -Wno-unused-result - -Wno-format-security # TODO: disable that when we'll have time to fix every printf format issue - -Wno-nested-anon-types - ) - set(cxx_local_opts - -std=c++20 - -pthread - -fexceptions - -fnon-call-exceptions - -pipe - -ffast-math - # clang -specific: - # -fforce-emit-vtables - ) - set(cxx_compiler_options_common ${cxx_local_opts_warnings} ${cxx_local_opts} ${CXX_FLAGS_EXTRA}) + set(cxx_compiler_options_common ${list_gnu_explicit_compiler_options_all} ${CXX_FLAGS_EXTRA}) #separate_arguments(cxx_compiler_options_common) - # GCC flags not supported by clang: - - # MemorySanitizer: it doesn't work out of the box. It needs to be linked to an MSAN-instrumented build of libc++ and libc++abi. - # This means: one should build them from LLVM source... - # https://github.com/google/sanitizers/wiki/MemorySanitizerLibcxxHowTo - #IF (${USE_MSAN}) - # SET (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++") - #ENDIF() - # Use "-stdlib=libstdc++" to link against GCC c/c++ libs (this is done by default) - # To use LLVM libc++ use "-stdlib=libc++", but you need to install it separately - #-- Apply compiler flags, only the ones specific per build type. # -fno-omit-frame-pointer disables a good optimization which may corrupt the debugger stack trace. - set(COMPILE_OPTIONS_EXTRA) + set(local_compile_options_extra) if(ENABLED_SANITIZER OR TARGET spheresvr_debug) - set(COMPILE_OPTIONS_EXTRA -fno-omit-frame-pointer -fno-inline) + set(local_compile_options_extra -fno-omit-frame-pointer -fno-inline) endif() if(TARGET spheresvr_release) target_compile_options( spheresvr_release - PUBLIC -O3 -flto=full -fvirtual-function-elimination ${COMPILE_OPTIONS_EXTRA} + PUBLIC -O3 -flto=full -fvirtual-function-elimination ${local_compile_options_extra} ) endif() if(TARGET spheresvr_nightly) if(ENABLED_SANITIZER) - target_compile_options(spheresvr_nightly PUBLIC -ggdb3 -Og ${COMPILE_OPTIONS_EXTRA}) + target_compile_options(spheresvr_nightly PUBLIC -ggdb3 -Og ${local_compile_options_extra}) else() target_compile_options( spheresvr_nightly - PUBLIC -O3 -flto=full -fvirtual-function-elimination ${COMPILE_OPTIONS_EXTRA} + PUBLIC -O3 -flto=full -fvirtual-function-elimination ${local_compile_options_extra} ) endif() endif() if(TARGET spheresvr_debug) - target_compile_options(spheresvr_debug PUBLIC -ggdb3 -O0 ${COMPILE_OPTIONS_EXTRA}) + target_compile_options(spheresvr_debug PUBLIC -ggdb3 -O0 ${local_compile_options_extra}) endif() #-- Store common linker flags. - if(${USE_MSAN}) - set(CMAKE_EXE_LINKER_FLAGS_EXTRA ${CMAKE_EXE_LINKER_FLAGS_EXTRA} -pie) - endif() set(cxx_linker_options_common + ${list_gnu_explicit_linker_options_all} ${CMAKE_EXE_LINKER_FLAGS_EXTRA} - -pthread - -dynamic - -Wl,--fatal-warnings $<$: -static-libstdc++ -static-libgcc> # no way to safely statically link against libc @@ -222,7 +90,7 @@ See comments in the toolchain and: https://github.com/google/sanitizers/wiki/Mem target_compile_options(${tgt} PRIVATE ${cxx_compiler_options_common}) target_compile_definitions(${tgt} PRIVATE ${cxx_compiler_definitions_common}) target_link_options(${tgt} PRIVATE ${cxx_linker_options_common}) - target_link_libraries(${tgt} PRIVATE ${LIB_mariadb_WITH_PATH} ${LIB_dl_WITH_PATH}) + target_link_libraries(${tgt} PRIVATE ${lib_mariadb_with_path} ${lib_dl_with_path}) endforeach() #-- Set different output folders for each build type diff --git a/cmake/toolchains/include/Linux-GNU_common.inc.cmake b/cmake/toolchains/include/Linux-GNU_common.inc.cmake index 90c80b83f..ce705b3a6 100644 --- a/cmake/toolchains/include/Linux-GNU_common.inc.cmake +++ b/cmake/toolchains/include/Linux-GNU_common.inc.cmake @@ -9,164 +9,42 @@ function(toolchain_exe_stuff_common) message(STATUS "Locating libraries to be linked to...") - set(LIBS_LINK_LIST mariadb dl) - foreach(LIB_NAME ${LIBS_LINK_LIST}) - find_library(LIB_${LIB_NAME}_WITH_PATH ${LIB_NAME} PATH ${lib_search_paths}) - message(STATUS "Library ${LIB_NAME}: ${LIB_${LIB_NAME}_WITH_PATH}") + set(libs_link_list mariadb dl) + foreach(lib_name ${libs_link_list}) + find_library(lib_${lib_name}_with_path ${lib_name} PATH ${lib_search_paths}) + message(STATUS "Library ${lib_name}: ${lib_${lib_name}_with_path}") endforeach() - #-- Validate sanitizers options and store them between the common compiler flags. - - set(ENABLED_SANITIZER false) - - if(${USE_ASAN}) - set(CXX_FLAGS_EXTRA - ${CXX_FLAGS_EXTRA} - -fsanitize=address - -fno-sanitize-recover=address - #-fsanitize-cfi # cfi: control flow integrity, not supported by GCC - -fsanitize-address-use-after-scope - -fsanitize=pointer-compare - -fsanitize=pointer-subtract - # Flags for additional instrumentation not strictly needing asan to be enabled - #-fvtable-verify=preinit # This causes a GCC internal error! Tested with 13.2.0 - -fstack-check - -fstack-protector-all - -fcf-protection=full - # GCC 14? - #-fharden-control-flow-redundancy - #-fhardcfr-check-exceptions - # Other - #-fsanitize-trap=all - ) - set(CMAKE_EXE_LINKER_FLAGS_EXTRA - ${CMAKE_EXE_LINKER_FLAGS_EXTRA} - -fsanitize=address - $<$:-static-libasan> - ) - set(PREPROCESSOR_DEFS_EXTRA ${PREPROCESSOR_DEFS_EXTRA} ADDRESS_SANITIZER) - set(ENABLED_SANITIZER true) - endif() - if(${USE_MSAN}) - message(FATAL_ERROR "Linux GCC doesn't yet support MSAN") - set(USE_MSAN false) - #SET (CXX_FLAGS_EXTRA ${CXX_FLAGS_EXTRA} -fsanitize=memory -fsanitize-memory-track-origins=2 -fPIE) - #set (CMAKE_EXE_LINKER_FLAGS_EXTRA ${CMAKE_EXE_LINKER_FLAGS_EXTRA} -fsanitize=memory )#$<$:-static-libmsan>) - #SET (PREPROCESSOR_DEFS_EXTRA ${PREPROCESSOR_DEFS_EXTRA} MEMORY_SANITIZER) - #SET (ENABLED_SANITIZER true) - endif() - if(${USE_LSAN}) - set(CXX_FLAGS_EXTRA ${CXX_FLAGS_EXTRA} -fsanitize=leak) - set(CMAKE_EXE_LINKER_FLAGS_EXTRA - ${CMAKE_EXE_LINKER_FLAGS_EXTRA} - -fsanitize=leak - $<$:-static-liblsan> - ) - set(PREPROCESSOR_DEFS_EXTRA ${PREPROCESSOR_DEFS_EXTRA} LEAK_SANITIZER) - set(ENABLED_SANITIZER true) - endif() - if(${USE_UBSAN}) - set(UBSAN_FLAGS - -fsanitize=undefined,float-divide-by-zero - -fno-sanitize=enum - # Unsupported (yet?) by GCC 13 - #-fsanitize=unsigned-integer-overflow #Unlike signed integer overflow, this is not undefined behavior, but it is often unintentional. - #-fsanitize=implicit-conversion, local-bounds - ) - set(CXX_FLAGS_EXTRA ${CXX_FLAGS_EXTRA} ${UBSAN_FLAGS} -fsanitize=return,vptr) - set(CMAKE_EXE_LINKER_FLAGS_EXTRA - ${CMAKE_EXE_LINKER_FLAGS_EXTRA} - -fsanitize=undefined - $<$:-static-libubsan> - ) - set(PREPROCESSOR_DEFS_EXTRA ${PREPROCESSOR_DEFS_EXTRA} UNDEFINED_BEHAVIOR_SANITIZER) - set(ENABLED_SANITIZER true) - endif() - - if(${ENABLED_SANITIZER}) - set(PREPROCESSOR_DEFS_EXTRA ${PREPROCESSOR_DEFS_EXTRA} _SANITIZERS) - endif() - #-- Store compiler flags common to all builds. - set(cxx_local_opts_warnings - -Werror - -Wall - -Wextra - -Wpedantic - - -Wmissing-include-dirs # Warns when an include directory provided with -I does not exist. - -Wformat=2 - #-Wcast-qual # Warns about casts that remove a type's const or volatile qualifier. - #-Wconversion # Temporarily disabled. Warns about implicit type conversions that might change a value, such as narrowing conversions. - -Wdisabled-optimization - #-Winvalid-pch - -Wzero-as-null-pointer-constant - #-Wnull-dereference # Don't: on GCC 12 causes some false positives... - -Wduplicated-cond - - # Supported by Clang, but unsupported by GCC: - #-Wweak-vtables - - # Unsupported by Clang, but supported by GCC: - -Wtrampolines # Warns when trampolines (a technique to implement nested functions) are generated (don't want this for security reasons). - -Wvector-operation-performance - -Wsized-deallocation - -Wduplicated-cond - -Wshift-overflow=2 - - # Disable errors: - -Wno-format-nonliteral # Since -Wformat=2 is stricter, you would need to disable this warning. - -Wno-nonnull-compare # GCC only - -Wno-switch - -Wno-implicit-fallthrough - -Wno-parentheses - -Wno-misleading-indentation - -Wno-unused-result - -Wno-format-security # TODO: disable that when we'll have time to fix every printf format issue - -Wno-nested-anon-types - ) - set(cxx_local_opts - -std=c++20 - -pthread - -fexceptions - -fnon-call-exceptions - -pipe - -ffast-math - ) - set(cxx_compiler_options_common ${cxx_local_opts_warnings} ${cxx_local_opts} ${CXX_FLAGS_EXTRA}) + set(cxx_compiler_options_common ${list_gnu_explicit_compiler_options_all} ${CXX_FLAGS_EXTRA}) #-- Apply compiler flags, only the ones specific per build type. # -fno-omit-frame-pointer disables a good optimization which may corrupt the debugger stack trace. - set(COMPILE_OPTIONS_EXTRA) + set(local_compile_options_extra) if(ENABLED_SANITIZER OR TARGET spheresvr_debug) - set(COMPILE_OPTIONS_EXTRA -fno-omit-frame-pointer -fno-inline) + set(local_compile_options_extra -fno-omit-frame-pointer -fno-inline) endif() if(TARGET spheresvr_release) - target_compile_options(spheresvr_release PUBLIC -s -O3 ${COMPILE_OPTIONS_EXTRA}) + target_compile_options(spheresvr_release PUBLIC -s -O3 ${local_compile_options_extra}) endif() if(TARGET spheresvr_nightly) if(ENABLED_SANITIZER) - target_compile_options(spheresvr_nightly PUBLIC -ggdb3 -Og ${COMPILE_OPTIONS_EXTRA}) + target_compile_options(spheresvr_nightly PUBLIC -ggdb3 -Og ${local_compile_options_extra}) else() - target_compile_options(spheresvr_nightly PUBLIC -O3 ${COMPILE_OPTIONS_EXTRA}) + target_compile_options(spheresvr_nightly PUBLIC -O3 ${local_compile_options_extra}) endif() endif() if(TARGET spheresvr_debug) - target_compile_options(spheresvr_debug PUBLIC -ggdb3 -O0 ${COMPILE_OPTIONS_EXTRA}) + target_compile_options(spheresvr_debug PUBLIC -ggdb3 -O0 ${local_compile_options_extra}) endif() #-- Store common linker flags. - if(${USE_MSAN}) - set(CMAKE_EXE_LINKER_FLAGS_EXTRA ${CMAKE_EXE_LINKER_FLAGS_EXTRA} -pie) - endif() set(cxx_linker_options_common + ${list_gnu_explicit_linker_options_all} ${CMAKE_EXE_LINKER_FLAGS_EXTRA} - -pthread - -dynamic - -Wl,--fatal-warnings $<$: -static-libstdc++ -static-libgcc # no way to safely statically link against libc @@ -202,7 +80,7 @@ function(toolchain_exe_stuff_common) target_compile_options(${tgt} PRIVATE ${cxx_compiler_options_common}) target_compile_definitions(${tgt} PRIVATE ${cxx_compiler_definitions_common}) target_link_options(${tgt} PRIVATE ${cxx_linker_options_common}) - target_link_libraries(${tgt} PRIVATE ${LIB_mariadb_WITH_PATH} ${LIB_dl_WITH_PATH}) + target_link_libraries(${tgt} PRIVATE ${lib_mariadb_with_path} ${lib_dl_with_path}) endforeach() #-- Set different output folders for each build type diff --git a/cmake/toolchains/include/OSX-AppleClang_common.inc.cmake b/cmake/toolchains/include/OSX-AppleClang_common.inc.cmake index 62088924a..fb877cffe 100644 --- a/cmake/toolchains/include/OSX-AppleClang_common.inc.cmake +++ b/cmake/toolchains/include/OSX-AppleClang_common.inc.cmake @@ -9,143 +9,49 @@ function(toolchain_exe_stuff_common) message(STATUS "Locating libraries to be linked to...") - set(LIBS_LINK_LIST mariadb dl) - foreach(LIB_NAME ${LIBS_LINK_LIST}) + set(libs_link_list mariadb dl) + foreach(lib_name ${libs_link_list}) find_library( - LIB_${LIB_NAME}_WITH_PATH - ${LIB_NAME} + lib_${lib_name}_with_path + ${lib_name} HINT "/usr/local/opt/mariadb-connector-c/lib/mariadb" "/opt/homebrew/var/mariadb-connector-c/lib/mariadb" "/opt/homebrew/lib/mariadb" ) - message(STATUS "Library ${LIB_NAME}: ${LIB_${LIB_NAME}_WITH_PATH}") + message(STATUS "Library ${lib_name}: ${lib_${lib_name}_with_path}") endforeach() - #-- Validate sanitizers options and store them between the common compiler flags. - - set(ENABLED_SANITIZER false) - # From https://clang.llvm.org/docs/ClangCommandLineReference.html - # -static-libsan Statically link the sanitizer runtime (Not supported for ASan, TSan or UBSan on darwin) - - if(${USE_ASAN}) - set(CXX_FLAGS_EXTRA - ${CXX_FLAGS_EXTRA} # -fsanitize=safe-stack # Can't be used with asan! - -fsanitize=address - -fno-sanitize-recover=address #-fsanitize-cfi # cfi: control flow integrity - -fsanitize-address-use-after-scope - -fsanitize=pointer-compare - -fsanitize=pointer-subtract - # Flags for additional instrumentation not strictly needing asan to be enabled - -fcf-protection=full - -fstack-check - -fstack-protector-all - -fstack-clash-protection - # Not supported by Clang, but supported by GCC - #-fvtable-verify=preinit -fharden-control-flow-redundancy -fhardcfr-check-exceptions - # Other - #-fsanitize-trap=all - ) - set(CMAKE_EXE_LINKER_FLAGS_EXTRA ${CMAKE_EXE_LINKER_FLAGS_EXTRA} -fsanitize=address) - set(PREPROCESSOR_DEFS_EXTRA ${PREPROCESSOR_DEFS_EXTRA} ADDRESS_SANITIZER) - set(ENABLED_SANITIZER true) - endif() - if(${USE_MSAN}) - set(CXX_FLAGS_EXTRA ${CXX_FLAGS_EXTRA} -fsanitize=memory -fsanitize-memory-track-origins=2 -fPIE) - set(CMAKE_EXE_LINKER_FLAGS_EXTRA ${CMAKE_EXE_LINKER_FLAGS_EXTRA} -fsanitize=memory) - set(PREPROCESSOR_DEFS_EXTRA ${PREPROCESSOR_DEFS_EXTRA} MEMORY_SANITIZER) - set(ENABLED_SANITIZER true) - endif() - if(${USE_LSAN}) - set(CXX_FLAGS_EXTRA ${CXX_FLAGS_EXTRA} -fsanitize=leak) - set(CMAKE_EXE_LINKER_FLAGS_EXTRA ${CMAKE_EXE_LINKER_FLAGS_EXTRA} -fsanitize=leak) - set(PREPROCESSOR_DEFS_EXTRA ${PREPROCESSOR_DEFS_EXTRA} LEAK_SANITIZER) - set(ENABLED_SANITIZER true) - endif() - if(${USE_UBSAN}) - set(UBSAN_FLAGS - -fsanitize=undefined,float-divide-by-zero,local-bounds - -fno-sanitize=enum - # Supported? - -fsanitize=unsigned-integer-overflow #Unlike signed integer overflow, this is not undefined behavior, but it is often unintentional. - -fsanitize=implicit-conversion - ) - set(CXX_FLAGS_EXTRA ${CXX_FLAGS_EXTRA} ${UBSAN_FLAGS} -fsanitize=return,vptr) - set(CMAKE_EXE_LINKER_FLAGS_EXTRA ${CMAKE_EXE_LINKER_FLAGS_EXTRA} -fsanitize=undefined) - set(PREPROCESSOR_DEFS_EXTRA ${PREPROCESSOR_DEFS_EXTRA} UNDEFINED_BEHAVIOR_SANITIZER) - set(ENABLED_SANITIZER true) - endif() - - if(${ENABLED_SANITIZER}) - set(PREPROCESSOR_DEFS_EXTRA ${PREPROCESSOR_DEFS_EXTRA} _SANITIZERS) - set(CMAKE_EXE_LINKER_FLAGS_EXTRA - ${CMAKE_EXE_LINKER_FLAGS_EXTRA} - $<$:-static-libsan> - ) - endif() - #-- Store compiler flags common to all builds. - set(cxx_local_opts_warnings - -Werror - -Wall - -Wextra - -Wno-unknown-pragmas - -Wno-switch - -Wno-implicit-fallthrough - -Wno-parentheses - -Wno-misleading-indentation - -Wno-conversion-null - -Wno-unused-result - -Wno-format-security # TODO: disable that when we'll have time to fix every printf format issue - # clang-specific: - -Wno-deprecated-declarations # spams so much warnings for the use of sprintf - ) - set(cxx_local_opts - -std=c++20 - -pthread - -fexceptions - -fnon-call-exceptions - -pipe - -ffast-math - ) - set(cxx_compiler_options_common ${cxx_local_opts_warnings} ${cxx_local_opts} ${CXX_FLAGS_EXTRA}) - - # GCC flags not supported by clang: - # Warnings: "-Wno-nonnull-compare -Wno-maybe-uninitialized" - # Other: "-fno-expensive-optimizations" + set(cxx_compiler_options_common ${list_gnu_explicit_compiler_options_all} ${cxx_local_opts} ${CXX_FLAGS_EXTRA}) #-- Apply compiler flags, only the ones specific per build type. # -fno-omit-frame-pointer disables a good optimization which may corrupt the debugger stack trace. - set(COMPILE_OPTIONS_EXTRA) + set(local_compile_options_extra) if(ENABLED_SANITIZER OR TARGET spheresvr_debug) - set(COMPILE_OPTIONS_EXTRA -fno-omit-frame-pointer -fno-inline) + set(local_compile_options_extra -fno-omit-frame-pointer -fno-inline) endif() if(TARGET spheresvr_release) - target_compile_options(spheresvr_release PUBLIC -O3 ${COMPILE_OPTIONS_EXTRA}) + target_compile_options(spheresvr_release PUBLIC -O3 ${local_compile_options_extra}) endif() if(TARGET spheresvr_nightly) if(ENABLED_SANITIZER) - target_compile_options(spheresvr_nightly PUBLIC -ggdb3 -Og ${COMPILE_OPTIONS_EXTRA}) + target_compile_options(spheresvr_nightly PUBLIC -ggdb3 -Og ${local_compile_options_extra}) else() - target_compile_options(spheresvr_nightly PUBLIC -O3 ${COMPILE_OPTIONS_EXTRA}) + target_compile_options(spheresvr_nightly PUBLIC -O3 ${local_compile_options_extra}) endif() endif() if(TARGET spheresvr_debug) - target_compile_options(spheresvr_debug PUBLIC -ggdb3 -O0 ${COMPILE_OPTIONS_EXTRA}) + target_compile_options(spheresvr_debug PUBLIC -ggdb3 -O0 ${local_compile_options_extra}) endif() #-- Store common linker flags. - if(${USE_MSAN}) - set(CMAKE_EXE_LINKER_FLAGS_EXTRA ${CMAKE_EXE_LINKER_FLAGS_EXTRA} -pie) - endif() set(cxx_linker_options_common + ${list_gnu_explicit_linker_options_all} ${CMAKE_EXE_LINKER_FLAGS_EXTRA} - -pthread - -dynamic - -Wl,-fatal_warnings $<$: -static-libstdc++ -static-libgcc> # no way to statically link against libc @@ -188,7 +94,7 @@ function(toolchain_exe_stuff_common) target_compile_options(${tgt} PRIVATE ${cxx_compiler_options_common}) target_compile_definitions(${tgt} PRIVATE ${cxx_compiler_definitions_common}) target_link_options(${tgt} PRIVATE ${cxx_linker_options_common}) - target_link_libraries(${tgt} PRIVATE ${LIB_mariadb_WITH_PATH} ${LIB_dl_WITH_PATH}) + target_link_libraries(${tgt} PRIVATE ${lib_mariadb_with_path} ${lib_dl_with_path}) endforeach() #-- Set different output folders for each build type diff --git a/cmake/toolchains/include/Windows-Clang_common.inc.cmake b/cmake/toolchains/include/Windows-Clang_common.inc.cmake index a502a5185..7e7f9f30c 100644 --- a/cmake/toolchains/include/Windows-Clang_common.inc.cmake +++ b/cmake/toolchains/include/Windows-Clang_common.inc.cmake @@ -24,125 +24,26 @@ function(toolchain_exe_stuff_common) endif() endif() - #-- Validate sanitizers options and store them between the common compiler flags. - - set(ENABLED_SANITIZER false) - # From https://clang.llvm.org/docs/ClangCommandLineReference.html - # -static-libsan Statically link the sanitizer runtime (Not supported for ASan, TSan or UBSan on darwin) - - if(${USE_ASAN}) - set(CXX_FLAGS_EXTRA - ${CXX_FLAGS_EXTRA} # -fsanitize=safe-stack # Can't be used with asan! - -fsanitize=address - -fno-sanitize-recover=address #-fsanitize-cfi # cfi: control flow integrity - -fsanitize-address-use-after-scope - -fsanitize=pointer-compare - -fsanitize=pointer-subtract - # Flags for additional instrumentation not strictly needing asan to be enabled - -fcf-protection=full - -fstack-check - -fstack-protector-all - -fstack-clash-protection - # Not supported by Clang, but supported by GCC - #-fvtable-verify=preinit -fharden-control-flow-redundancy -fhardcfr-check-exceptions - # Other - #-fsanitize-trap=all - ) - if(${CLANG_USE_GCC_LINKER}) - set(CMAKE_EXE_LINKER_FLAGS_EXTRA ${CMAKE_EXE_LINKER_FLAGS_EXTRA} -fsanitize=address) - endif() - set(PREPROCESSOR_DEFS_EXTRA ${PREPROCESSOR_DEFS_EXTRA} ADDRESS_SANITIZER) - set(ENABLED_SANITIZER true) - endif() - if(${USE_MSAN}) - message(FATAL_ERROR "Windows Clang doesn't yet support MSAN") - set(USE_MSAN false) - #SET (CXX_FLAGS_EXTRA ${CXX_FLAGS_EXTRA} -fsanitize=memory -fsanitize-memory-track-origins=2 -fPIE) - #IF (${CLANG_USE_GCC_LINKER}) - #set (CMAKE_EXE_LINKER_FLAGS_EXTRA ${CMAKE_EXE_LINKER_FLAGS_EXTRA} -fsanitize=memory) - #ENDIF - #SET (PREPROCESSOR_DEFS_EXTRA ${PREPROCESSOR_DEFS_EXTRA} MEMORY_SANITIZER) - #SET (ENABLED_SANITIZER true) - endif() - if(${USE_LSAN}) - message(FATAL_ERROR "Windows Clang doesn't yet support LSAN") - set(USE_LSAN false) - #SET (CXX_FLAGS_EXTRA ${CXX_FLAGS_EXTRA} -fsanitize=leak) - #IF (${CLANG_USE_GCC_LINKER}) - #set (CMAKE_EXE_LINKER_FLAGS_EXTRA ${CMAKE_EXE_LINKER_FLAGS_EXTRA} -fsanitize=leak) - #ENDIF - #SET (PREPROCESSOR_DEFS_EXTRA ${PREPROCESSOR_DEFS_EXTRA} LEAK_SANITIZER) - #SET (ENABLED_SANITIZER true) - endif() - if(${USE_UBSAN}) - set(UBSAN_FLAGS - -fsanitize=undefined,float-divide-by-zero,local-bounds - -fno-sanitize=enum - # Supported? - -fsanitize=unsigned-integer-overflow #Unlike signed integer overflow, this is not undefined behavior, but it is often unintentional. - -fsanitize=implicit-conversion - ) - set(CXX_FLAGS_EXTRA ${CXX_FLAGS_EXTRA} ${UBSAN_FLAGS} -fsanitize=return) - #IF (${CLANG_USE_GCC_LINKER}) - #set (CMAKE_EXE_LINKER_FLAGS_EXTRA ${CMAKE_EXE_LINKER_FLAGS_EXTRA} -fsanitize=undefined) - #ENDIF - set(PREPROCESSOR_DEFS_EXTRA ${PREPROCESSOR_DEFS_EXTRA} UNDEFINED_BEHAVIOR_SANITIZER) - set(ENABLED_SANITIZER true) - endif() - - if(${ENABLED_SANITIZER}) - set(PREPROCESSOR_DEFS_EXTRA ${PREPROCESSOR_DEFS_EXTRA} _SANITIZERS) - if(${RUNTIME_STATIC_LINK}) - set(CMAKE_EXE_LINKER_FLAGS_EXTRA ${CMAKE_EXE_LINKER_FLAGS_EXTRA} -static-libsan) - else() - set(CMAKE_EXE_LINKER_FLAGS_EXTRA ${CMAKE_EXE_LINKER_FLAGS_EXTRA} -shared-libsan) - endif() - endif() - #-- Store compiler flags common to all builds. - set(cxx_local_opts_warnings - -Werror - -Wall - -Wextra - -Wno-unknown-pragmas - -Wno-switch - -Wno-implicit-fallthrough - -Wno-parentheses - -Wno-misleading-indentation - -Wno-conversion-null - -Wno-unused-result - -Wno-format-security # TODO: disable that when we'll have time to fix every printf format issue - # clang -specific: - # -fforce-emit-vtables - ) set(cxx_local_opts - -std=c++20 - -fexceptions - -fnon-call-exceptions - -pipe - -ffast-math -mno-ms-bitfields # -mno-ms-bitfields is needed to fix structure packing; # -pthread unused here? we only need to specify that to the linker? - -Wno-format-security # TODO: disable that when we'll have time to fix every printf format issue - # clang-specific: - # - # Flags supported by GCC but not by Clang: -fno-expensive-optimizations, -Wno-error=maybe-uninitialized ) - set(cxx_compiler_options_common ${cxx_local_opts_warnings} ${cxx_local_opts} ${CXX_FLAGS_EXTRA}) + set(cxx_compiler_options_common ${list_gnu_explicit_compiler_options_all} ${cxx_local_opts} ${CXX_FLAGS_EXTRA}) #-- Apply compiler flags, only the ones specific per build type. # -fno-omit-frame-pointer disables a good optimization which may corrupt the debugger stack trace. - set(COMPILE_OPTIONS_EXTRA) + set(local_compile_options_extra) if(ENABLED_SANITIZER OR TARGET spheresvr_debug) - set(COMPILE_OPTIONS_EXTRA -fno-omit-frame-pointer -fno-inline) + set(local_compile_options_extra -fno-omit-frame-pointer -fno-inline) endif() if(TARGET spheresvr_release) target_compile_options( spheresvr_release - PUBLIC -O3 -flto=full -fvirtual-function-elimination ${COMPILE_OPTIONS_EXTRA} + PUBLIC -O3 -flto=full -fvirtual-function-elimination ${local_compile_options_extra} ) #[[ IF (NOT ${CLANG_USE_GCC_LINKER}) @@ -156,11 +57,11 @@ function(toolchain_exe_stuff_common) endif() if(TARGET spheresvr_nightly) if(ENABLED_SANITIZER) - target_compile_options(spheresvr_nightly PUBLIC -ggdb3 -Og ${COMPILE_OPTIONS_EXTRA}) + target_compile_options(spheresvr_nightly PUBLIC -ggdb3 -Og ${local_compile_options_extra}) else() target_compile_options( spheresvr_nightly - PUBLIC -O3 -flto=full -fvirtual-function-elimination ${COMPILE_OPTIONS_EXTRA} + PUBLIC -O3 -flto=full -fvirtual-function-elimination ${local_compile_options_extra} ) endif() #[[ @@ -188,17 +89,13 @@ function(toolchain_exe_stuff_common) #-- Store common linker flags. - if(${USE_MSAN}) - set(CMAKE_EXE_LINKER_FLAGS_EXTRA ${CMAKE_EXE_LINKER_FLAGS_EXTRA} -pie) - endif() - set(cxx_linker_options_common ${CMAKE_EXE_LINKER_FLAGS_EXTRA}) if(${CLANG_USE_GCC_LINKER}) - set(cxx_linker_options_common ${cxx_linker_options_common} -pthread -dynamic -Wl,--fatal-warnings) + set(cxx_linker_options_common ${list_gnu_explicit_linker_options_all}) if(${RUNTIME_STATIC_LINK}) set(cxx_linker_options_common ${cxx_linker_options_common} -static-libstdc++ -static-libgcc) # no way to statically link against libc? maybe we can on windows? endif() - #[[ +#[[ else () if (${RUNTIME_STATIC_LINK}) set (cxx_linker_options_common ${cxx_linker_options_common} /MTd ) @@ -282,7 +179,7 @@ function(toolchain_exe_stuff_common) endif () endif() endif () -]] + ]] endif() set(libs_to_link_against ${libs_to_link_against} ws2_32 ${libs_prefix}mariadb) diff --git a/cmake/toolchains/include/Windows-GNU_common.inc.cmake b/cmake/toolchains/include/Windows-GNU_common.inc.cmake index efbffb09b..58f2866df 100644 --- a/cmake/toolchains/include/Windows-GNU_common.inc.cmake +++ b/cmake/toolchains/include/Windows-GNU_common.inc.cmake @@ -16,150 +16,38 @@ function(toolchain_exe_stuff_common) ## add_link_options ("LINKER:SHELL:-mwindows") #ENDIF () - #-- Validate sanitizers options and store them between the common compiler flags. - - set(ENABLED_SANITIZER false) - if(${USE_ASAN}) - message(FATAL_ERROR "MinGW-GCC doesn't yet support ASAN") - set(USE_ASAN false) - #[[ - SET (CXX_FLAGS_EXTRA ${CXX_FLAGS_EXTRA} - -fsanitize=address -fno-sanitize-recover=address #-fsanitize-cfi # cfi: control flow integrity, not currently supported by GCC (even on Linux) - -fsanitize-address-use-after-scope -fsanitize=pointer-compare -fsanitize=pointer-subtract - # Flags for additional instrumentation not strictly needing asan to be enabled - #-fvtable-verify=preinit # This causes a GCC internal error! Tested with 13.2.0 - -fstack-check -fstack-protector-all - -fcf-protection=full - # GCC 14? - #-fharden-control-flow-redundancy -fhardcfr-check-exceptions - # Other - #-fsanitize-trap=all - ) - ]] - #set (CMAKE_EXE_LINKER_FLAGS_EXTRA ${CMAKE_EXE_LINKER_FLAGS_EXTRA} -fsanitize=address $<$:-static-libasan>) - #SET (PREPROCESSOR_DEFS_EXTRA ${PREPROCESSOR_DEFS_EXTRA} ADDRESS_SANITIZER) - #SET (ENABLED_SANITIZER true) - endif() - if(${USE_MSAN}) - message(FATAL_ERROR "MinGW-GCC doesn't yet support MSAN") - set(USE_MSAN false) - #SET (CXX_FLAGS_EXTRA ${CXX_FLAGS_EXTRA} -fsanitize=memory -fsanitize-memory-track-origins=2 -fPIE) - #set (CMAKE_EXE_LINKER_FLAGS_EXTRA ${CMAKE_EXE_LINKER_FLAGS_EXTRA} -fsanitize=memory )#$<$:-static-libmsan>) - #SET (PREPROCESSOR_DEFS_EXTRA ${PREPROCESSOR_DEFS_EXTRA} MEMORY_SANITIZER) - #SET (ENABLED_SANITIZER true) - endif() - if(${USE_LSAN}) - message(FATAL_ERROR "MinGW-GCC doesn't yet support LSAN") - set(USE_LSAN false) - #SET (CXX_FLAGS_EXTRA ${CXX_FLAGS_EXTRA} -fsanitize=leak) - #set (CMAKE_EXE_LINKER_FLAGS_EXTRA ${CMAKE_EXE_LINKER_FLAGS_EXTRA} -fsanitize=leak #$<$:-static-liblsan>) - #SET (PREPROCESSOR_DEFS_EXTRA ${PREPROCESSOR_DEFS_EXTRA} LEAK_SANITIZER) - #SET (ENABLED_SANITIZER true) - endif() - if(${USE_UBSAN}) - message(FATAL_ERROR "MinGW-GCC doesn't yet support UBSAN") - set(USE_UBSAN false) - #[[ - SET (UBSAN_FLAGS - -fsanitize=undefined,float-divide-by-zero - -fno-sanitize=enum - # Unsupported (yet?) by GCC 13 - #-fsanitize=unsigned-integer-overflow #Unlike signed integer overflow, this is not undefined behavior, but it is often unintentional. - #-fsanitize=implicit-conversion, local-bounds - ) - ]] - #SET (CXX_FLAGS_EXTRA ${CXX_FLAGS_EXTRA} ${UBSAN_FLAGS} -fsanitize=return,vptr) - #set (CMAKE_EXE_LINKER_FLAGS_EXTRA ${CMAKE_EXE_LINKER_FLAGS_EXTRA} -fsanitize=undefined #$<$:-static-libubsan>) - #SET (PREPROCESSOR_DEFS_EXTRA ${PREPROCESSOR_DEFS_EXTRA} UNDEFINED_BEHAVIOR_SANITIZER) - #SET (ENABLED_SANITIZER true) - endif() - - #IF (${ENABLED_SANITIZER}) - # SET (PREPROCESSOR_DEFS_EXTRA ${PREPROCESSOR_DEFS_EXTRA} _SANITIZERS) - #ENDIF () - - #-- Store compiler flags common to all builds. - - set(cxx_local_opts_warnings - -Werror - -Wall - -Wextra - -Wpedantic - - -Wmissing-include-dirs # Warns when an include directory provided with -I does not exist. - -Wformat=2 - #-Wcast-qual # Warns about casts that remove a type's const or volatile qualifier. - #-Wconversion # Temporarily disabled. Warns about implicit type conversions that might change a value, such as narrowing conversions. - -Wdisabled-optimization - #-Winvalid-pch - -Wzero-as-null-pointer-constant - #-Wnull-dereference # Don't: on GCC 12 causes some false positives... - -Wduplicated-cond - - # Supported by Clang, but unsupported by GCC: - #-Wweak-vtables - - # Unsupported by Clang, but supported by GCC: - -Wtrampolines # Warns when trampolines (a technique to implement nested functions) are generated (don't want this for security reasons). - -Wvector-operation-performance - -Wsized-deallocation - -Wduplicated-cond - -Wshift-overflow=2 - - # Disable errors: - -Wno-format-nonliteral # Since -Wformat=2 is stricter, you would need to disable this warning. - -Wno-nonnull-compare # GCC only - -Wno-switch - -Wno-implicit-fallthrough - -Wno-parentheses - -Wno-misleading-indentation - -Wno-unused-result - -Wno-format-security # TODO: disable that when we'll have time to fix every printf format issue - -Wno-nested-anon-types - ) set(cxx_local_opts - -std=c++20 - -pthread - -fexceptions - -fnon-call-exceptions - -mno-ms-bitfields # it's needed to fix structure packing - -pipe - -ffast-math + -mno-ms-bitfields # it's needed to fix structure packing ) - set(cxx_compiler_options_common ${cxx_local_opts_warnings} ${cxx_local_opts} ${CXX_FLAGS_EXTRA}) + set(cxx_compiler_options_common ${list_gnu_explicit_compiler_options_all} ${cxx_local_opts} ${CXX_FLAGS_EXTRA}) #-- Apply compiler flags, only the ones specific per build type. # -fno-omit-frame-pointer disables a good optimization which may corrupt the debugger stack trace. - set(COMPILE_OPTIONS_EXTRA) + set(local_compile_options_extra) if(ENABLED_SANITIZER OR TARGET spheresvr_debug) - set(COMPILE_OPTIONS_EXTRA -fno-omit-frame-pointer -fno-inline) + set(local_compile_options_extra -fno-omit-frame-pointer -fno-inline) endif() if(TARGET spheresvr_release) - target_compile_options(spheresvr_release PUBLIC -s -O3 ${COMPILE_OPTIONS_EXTRA}) + target_compile_options(spheresvr_release PUBLIC -s -O3 ${local_compile_options_extra}) endif() if(TARGET spheresvr_nightly) if(ENABLED_SANITIZER) - target_compile_options(spheresvr_nightly PUBLIC -ggdb3 -Og ${COMPILE_OPTIONS_EXTRA}) + target_compile_options(spheresvr_nightly PUBLIC -ggdb3 -Og ${local_compile_options_extra}) else() - target_compile_options(spheresvr_nightly PUBLIC -O3 ${COMPILE_OPTIONS_EXTRA}) + target_compile_options(spheresvr_nightly PUBLIC -O3 ${local_compile_options_extra}) endif() endif() if(TARGET spheresvr_debug) - target_compile_options(spheresvr_debug PUBLIC -ggdb3 -O0 ${COMPILE_OPTIONS_EXTRA}) + target_compile_options(spheresvr_debug PUBLIC -ggdb3 -O0 ${local_compile_options_extra}) endif() #-- Store common linker flags. - if(${USE_MSAN}) - set(CMAKE_EXE_LINKER_FLAGS_EXTRA ${CMAKE_EXE_LINKER_FLAGS_EXTRA} -pie) - endif() set(cxx_linker_options_common + ${list_gnu_explicit_linker_options_all} ${CMAKE_EXE_LINKER_FLAGS_EXTRA} - -pthread - -dynamic - -Wl,--fatal-warnings $<$: -static-libstdc++ -static-libgcc> # no way to statically link against libc? maybe we can on windows? diff --git a/src/common/CExpression.cpp b/src/common/CExpression.cpp index 550a177ad..8a530cb15 100644 --- a/src/common/CExpression.cpp +++ b/src/common/CExpression.cpp @@ -1230,18 +1230,18 @@ int CExpression::GetConditionalSubexpressions(lptstr& pExpr, SubexprData(&psSube } // Helper lambda functions for the next section. - auto findLastClosingBracket = [](lptstr pExpr) -> lptstr + auto findLastClosingBracket = [](lptstr pExpr_) -> lptstr { // Returns a pointer to the last closing bracket in the string. // If the last character in the string (ignoring comments) is not ')', it means that, if we find a closing bracket, // it's past other characters, so there's other valid text after the ')'. // Eg: IF (1+2) > 10. The ')' is not at the end of the line, because there's the remaining part of the script. - ASSERT(*pExpr != '\0'); + ASSERT(*pExpr_ != '\0'); lptstr pExprFinder; - const size_t uiExprLength = strlen(pExpr); - const lptstr pComment = Str_FindSubstring(pExpr, "//", uiExprLength, 2); + const size_t uiExprLength = strlen(pExpr_); + const lptstr pComment = Str_FindSubstring(pExpr_, "//", uiExprLength, 2); if (nullptr == pComment) { - pExprFinder = pExpr + uiExprLength - 1; + pExprFinder = pExpr_ + uiExprLength - 1; // Now pExprFinder is at the end of the string } else { @@ -1256,28 +1256,28 @@ int CExpression::GetConditionalSubexpressions(lptstr& pExpr, SubexprData(&psSube --pExprFinder; else break; - } while (pExprFinder > pExpr); + } while (pExprFinder > pExpr_); return (*pExprFinder == ')') ? pExprFinder : nullptr; }; - auto skipBracketedSubexpression = [](lptstr pExpr) -> lptstr + auto skipBracketedSubexpression = [](lptstr pExpr_) -> lptstr { - ASSERT(*pExpr == '('); - tchar ch; + ASSERT(*pExpr_ == '('); + tchar ch_; uint uiOpenedCurlyBrackets = 1; while (uiOpenedCurlyBrackets != 0) // i'm interested only to the outermost range, not eventual sub-sub-sub-blah ranges { - ch = *(++pExpr); - if (ch == '(') + ch_ = *(++pExpr_); + if (ch_ == '(') ++uiOpenedCurlyBrackets; - else if (ch == ')') + else if (ch_ == ')') --uiOpenedCurlyBrackets; - else if (ch == '\0') + else if (ch_ == '\0') return nullptr; // Error } if (uiOpenedCurlyBrackets != 0) return nullptr; // Error - return pExpr; + return pExpr_; }; diff --git a/src/common/resource/sections/CDialogDef.cpp b/src/common/resource/sections/CDialogDef.cpp index f59e75719..ae31f1abb 100644 --- a/src/common/resource/sections/CDialogDef.cpp +++ b/src/common/resource/sections/CDialogDef.cpp @@ -144,25 +144,25 @@ bool CDialogDef::r_Verb( CScript & s, CTextConsole * pSrc ) // some command on t lptstr ptcArgs = s.GetArgStr(); //g_Log.EventDebug("Dialog index %d, KEY %s ARG %s.\n", index, ptcKey, ptcArgs); - const auto _SkipAll = [](lptstr& ptcArgs) noexcept -> void + const auto _SkipAll = [](lptstr& ptcArgs_) noexcept -> void { - SKIP_SEPARATORS(ptcArgs); - GETNONWHITESPACE(ptcArgs); + SKIP_SEPARATORS(ptcArgs_); + GETNONWHITESPACE(ptcArgs_); }; - const auto _CalcRelative = [](lptstr& ptcArgs, int &iCoordBase) -> int + const auto _CalcRelative = [](lptstr& ptcArgs_, int &iCoordBase_) -> int { int c; - if ( *ptcArgs == '-' && IsSpace(ptcArgs[1])) - c = iCoordBase, ++ptcArgs; - else if ( *ptcArgs == '+' ) - c = iCoordBase + Exp_GetSingle( ++ptcArgs ); - else if ( *ptcArgs == '-' ) - c = iCoordBase - Exp_GetSingle( ++ptcArgs ); - else if ( *ptcArgs == '*' ) - iCoordBase = c = iCoordBase + Exp_GetSingle( ++ptcArgs ); + if ( *ptcArgs_ == '-' && IsSpace(ptcArgs_[1])) + c = iCoordBase_, ++ptcArgs_; + else if ( *ptcArgs_ == '+' ) + c = iCoordBase_ + Exp_GetSingle( ++ptcArgs_ ); + else if ( *ptcArgs_ == '-' ) + c = iCoordBase_ - Exp_GetSingle( ++ptcArgs_ ); + else if ( *ptcArgs_ == '*' ) + iCoordBase_ = c = iCoordBase_ + Exp_GetSingle( ++ptcArgs_ ); else - c = Exp_GetSingle( ptcArgs ); + c = Exp_GetSingle( ptcArgs_ ); return c; }; diff --git a/src/game/chars/CCharUse.cpp b/src/game/chars/CCharUse.cpp index 8b9599e2f..56023d9f1 100644 --- a/src/game/chars/CCharUse.cpp +++ b/src/game/chars/CCharUse.cpp @@ -1125,9 +1125,9 @@ CChar * CChar::Use_Figurine( CItem * pItem, bool fCheckFollowerSlots ) std::optional iFollowerSlots; const bool fShouldCheckFollowerSlots = (fCheckFollowerSlots && IsSetOF(OF_PetSlots)); - auto _CheckFollowerSlots = [this](short iFollowerSlots) -> bool + auto _CheckFollowerSlots = [this](short iFollowerSlots_) -> bool { - if ( !FollowersUpdate(this, iFollowerSlots, true) ) + if ( !FollowersUpdate(this, iFollowerSlots_, true) ) { SysMessageDefault(DEFMSG_PETSLOTS_TRY_CONTROL); return false; diff --git a/src/game/components/CCSpawn.cpp b/src/game/components/CCSpawn.cpp index 7abcfe81a..746397e29 100644 --- a/src/game/components/CCSpawn.cpp +++ b/src/game/components/CCSpawn.cpp @@ -158,12 +158,12 @@ const CResourceDef* CCSpawn::_FixDef() if (pItem->IsType(IT_SPAWN_CHAR)) { - auto _TryChar = [this](CREID_TYPE idChar) -> const CResourceDef* + auto _TryChar = [this](CREID_TYPE idChar_) -> const CResourceDef* { - const CResourceDef* pResDef = CCharBase::FindCharBase(idChar); - if (pResDef) - _idSpawn = CResourceIDBase(RES_CHARDEF, idChar); - return pResDef; + const CResourceDef* pResDef_ = CCharBase::FindCharBase(idChar_); + if (pResDef_) + _idSpawn = CResourceIDBase(RES_CHARDEF, idChar_); + return pResDef_; }; CREID_TYPE idChar = (CREID_TYPE)iIndex; @@ -204,12 +204,12 @@ const CResourceDef* CCSpawn::_FixDef() } else if (pItem->IsType(IT_SPAWN_ITEM)) { - auto _TryItem = [this](ITEMID_TYPE idItem) -> const CResourceDef* + auto _TryItem = [this](ITEMID_TYPE idItem_) -> const CResourceDef* { - const CResourceDef* pResDef = CItemBase::FindItemBase(idItem); - if (pResDef) - _idSpawn = CResourceIDBase(RES_ITEMDEF, idItem); - return pResDef; + const CResourceDef* pResDef_ = CItemBase::FindItemBase(idItem_); + if (pResDef_) + _idSpawn = CResourceIDBase(RES_ITEMDEF, idItem_); + return pResDef_; }; ITEMID_TYPE idItem = (ITEMID_TYPE)iIndex; From 05b889d83c7bfc89954f7052da7096fc006011d6 Mon Sep 17 00:00:00 2001 From: cbnolok Date: Thu, 3 Oct 2024 13:19:48 +0200 Subject: [PATCH 11/32] Fixes and additions for FOLLOWERSLOTS, fix for LIST. - Fixed: LIST.ADD ignoring quoted arguments (Issue #1247). - Fixed: FOOD and MAXFOOD not being stored in the worldsave file (Issue #1289). - Added: CURFOLLOWER.CHARCOUNT, to return the raw number of characters you own/that are following you. Plain CURFOLLOWER returns the current total FOLLOWERSLOTS you own. - Changed: removed CURFOLLOWER.DEL and CURFOLLOWER.DELETE in favor of the more specific: CURFOLLOWER.DELUID: The same as .DEL/DELETE, just removed the pet via its UID. CURFOLLOWER.DELINDEX: Removes the pet via its id in the (cur)follower list for that owner. - Added: spells with SPELLFLAG_SUMMON now accept LOCAL.FollowerSlotsOverride in the triggers @Success and @SpellSuccess. Default value (do not override): -1. --- Changelog.txt | 9 ++ src/common/ListDefContMap.cpp | 37 ++++---- src/common/common.h | 7 +- src/game/chars/CChar.cpp | 46 +++++++++- src/game/chars/CChar.h | 2 +- src/game/chars/CCharSpell.cpp | 166 +++++++++++++++++++--------------- 6 files changed, 170 insertions(+), 97 deletions(-) diff --git a/Changelog.txt b/Changelog.txt index 210e47371..eb900a6b8 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -3902,3 +3902,12 @@ Added: 'H' shortcut for variables to get the value as hexadecimal. - Changed: added desired FollowerSlots as a second argument to CURFOLLOWER.ADD. Default value: its FollowerSlots. - Changed: @FollowerUpdate ARGN1 and ARGN2 are now read-only. Having them RW and actually get them working would have meant many other changes, breaking script compatibility. - Fixed: CURFOLLOWER.DEL/DELETE/CLEAR not working properly. + +03-10-2024, Nolok +- Fixed: LIST.ADD ignoring quoted arguments (Issue #1247). +- Fixed: FOOD and MAXFOOD not being stored in the worldsave file (Issue #1289). +- Added: CURFOLLOWER.CHARCOUNT, to return the raw number of characters you own/that are following you. Plain CURFOLLOWER returns the current total FOLLOWERSLOTS you own. +- Changed: removed CURFOLLOWER.DEL and CURFOLLOWER.DELETE in favor of the more specific: + CURFOLLOWER.DELUID: The same as .DEL/DELETE, just removed the pet via its UID. + CURFOLLOWER.DELINDEX: Removes the pet via its id in the (cur)follower list for that owner. +- Added: spells with SPELLFLAG_SUMMON now accept LOCAL.FollowerSlotsOverride in the triggers @Success and @SpellSuccess. Default value (do not override): -1. diff --git a/src/common/ListDefContMap.cpp b/src/common/ListDefContMap.cpp index 8d0d7c68b..d66757261 100644 --- a/src/common/ListDefContMap.cpp +++ b/src/common/ListDefContMap.cpp @@ -2,7 +2,6 @@ #include "../common/sphere_library/sstringobjs.h" #include "../common/CLog.h" #include "../sphere/threads.h" -#include "../game/CServerConfig.h" #include "CExpression.h" #include "CScript.h" #include "CTextConsole.h" @@ -269,7 +268,7 @@ bool CListDefCont::AddElementStr(lpctstr ptcKey) if ( (m_listElements.size() + 1) >= INTPTR_MAX ) // overflow? is it even useful? return false; - REMOVE_QUOTES( ptcKey ); + REMOVE_QUOTES( ptcKey ); m_listElements.emplace_back( new CListDefContStr(m_Key.GetBuffer(), ptcKey) ); @@ -774,14 +773,14 @@ bool CListDefMap::r_LoadVal( lpctstr ptcKey, CScript & s ) Str_Parse(ppCmds[0], &(ppCmds[1]), "." ); CListDefCont* pListBase = GetKey(ppCmds[0]); - lpctstr ptcArg = s.GetArgRaw(); + lpctstr ptcArg = s.GetArgRaw(); // LIST. if ( ppCmds[1] && *(ppCmds[1]) ) { Str_Parse(ppCmds[1], &(ppCmds[2]), "." ); - if ( !IsSimpleNumberString(ppCmds[1]) ) + if ( !IsStrNumeric(ppCmds[1]) ) { // LIST.. // Am i calling a valid operation? @@ -806,7 +805,7 @@ bool CListDefMap::r_LoadVal( lpctstr ptcKey, CScript & s ) m_Container.insert(pListBase); } - if ( IsSimpleNumberString(ptcArg) ) + if ( IsStrNumeric(ptcArg) ) return pListBase->AddElementNum(Exp_Get64Val(ptcArg)); else return pListBase->AddElementStr(ptcArg); @@ -830,22 +829,22 @@ bool CListDefMap::r_LoadVal( lpctstr ptcKey, CScript & s ) m_Container.insert(pListBase); } - tchar* ppCmd[2]; - ppCmd[0] = const_cast(ptcArg); - while ( Str_Parse( ppCmd[0], &(ppCmd[1]), "," )) + tchar* ppArgs[2]; + ppArgs[0] = const_cast(ptcArg); + while ( Str_Parse( ppArgs[0], &(ppArgs[1]), "," )) { - if ( IsSimpleNumberString(ppCmd[0]) ) - pListBase->AddElementNum(Exp_Get64Val(ppCmd[0])); + if ( IsStrNumeric(ppArgs[0]) ) + pListBase->AddElementNum(Exp_Get64Val(ppArgs[0])); else - pListBase->AddElementStr(ppCmd[0]); - ppCmd[0] = ppCmd[1]; + pListBase->AddElementStr(ppArgs[0]); + ppArgs[0] = ppArgs[1]; } //insert last element - if ( IsSimpleNumberString(ppCmd[0]) ) - return pListBase->AddElementNum(Exp_Get64Val(ppCmd[0])); + if ( IsStrNumeric(ppArgs[0]) ) + return pListBase->AddElementNum(Exp_Get64Val(ppArgs[0])); else - return pListBase->AddElementStr(ppCmd[0]); + return pListBase->AddElementStr(ppArgs[0]); } else if ( !strnicmp(ppCmds[1], "sort", 4) ) { @@ -889,7 +888,7 @@ bool CListDefMap::r_LoadVal( lpctstr ptcKey, CScript & s ) else if ( !strnicmp(ppCmds[2], "insert", 6) && ptcArg && *ptcArg ) { // Inserts at the nth index of LIST.xxx - const bool fIsNum = ( IsSimpleNumberString(ptcArg) ); + const bool fIsNum = ( IsStrNumeric(ptcArg) ); if ( nIndex >= pListBase->GetCount() ) { @@ -918,7 +917,7 @@ bool CListDefMap::r_LoadVal( lpctstr ptcKey, CScript & s ) if ( !pListElem ) return false; - if ( IsSimpleNumberString(ptcArg) ) + if ( IsStrNumeric(ptcArg) ) return pListBase->SetNumAt(nIndex, Exp_Get64Val(ptcArg)); else return pListBase->SetStrAt(nIndex, ptcArg); @@ -933,7 +932,7 @@ bool CListDefMap::r_LoadVal( lpctstr ptcKey, CScript & s ) pListBase = new CListDefCont(ppCmds[0]); m_Container.insert(pListBase); - if ( IsSimpleNumberString(ptcArg) ) + if ( IsStrNumeric(ptcArg) ) return pListBase->AddElementNum(Exp_Get64Val(ptcArg)); else return pListBase->AddElementStr(ptcArg); @@ -953,7 +952,7 @@ bool CListDefMap::r_LoadVal( lpctstr ptcKey, CScript & s ) m_Container.insert(pListBase); } - if ( IsSimpleNumberString(ptcArg) ) + if ( IsStrNumeric(ptcArg) ) return pListBase->AddElementNum(Exp_Get64Val(ptcArg)); else return pListBase->AddElementStr(ptcArg); diff --git a/src/common/common.h b/src/common/common.h index 65b68040d..5e75cc24a 100644 --- a/src/common/common.h +++ b/src/common/common.h @@ -131,8 +131,9 @@ constexpr T sign(const T n) noexcept /* Compiler/c++ language helpers */ // Ensure that a constexpr value or a generic expression is evaluated at compile time. +// Constexpr values are constants and cannot be mutated in the code. template -consteval T ensure_comptime(T&& val_) noexcept { +consteval T as_consteval(T&& val_) noexcept { return val_; } @@ -172,6 +173,10 @@ constexpr void UnreferencedParameter(T const&) noexcept { // Function specifier, like noexcept. Use this to make us know that the function code was checked and we know it can throw an exception. #define CANTHROW noexcept(false) +// To be used only as an helper marker, since there are functions with similar names intended to have different signatures and/or not be virtual. +// This means that we do NOT have forgotten to add the "virtual" qualifier, simply this method isn't virtual. +#define NONVIRTUAL + // Cpp attributes #define FALLTHROUGH [[fallthrough]] #define NODISCARD [[nodiscard]] diff --git a/src/game/chars/CChar.cpp b/src/game/chars/CChar.cpp index 42802a5b6..37058219e 100644 --- a/src/game/chars/CChar.cpp +++ b/src/game/chars/CChar.cpp @@ -2355,12 +2355,24 @@ bool CChar::r_WriteVal( lpctstr ptcKey, CSString & sVal, CTextConsole * pSrc, bo if (strlen(ptcKey) == 11) { + // This returns the total current follower slots. sVal.FormatSVal(GetCurFollowers()); return true; } sVal.FormatVal(0); ptcKey += 11; + if (*ptcKey != '.') + return false; + ptcKey += 1; + + if (!strnicmp(ptcKey, "CHARCOUNT", 9)) + { + sVal.FormatSTVal(m_followers.size()); + return true; + } + + // Access objects by ID. if (*ptcKey != '.' || m_followers.empty()) return false; @@ -3508,7 +3520,7 @@ bool CChar::r_LoadVal( CScript & s ) if (!s.HasArgs()) return false; - if (!strnicmp(ptcKey, "DELETE", 6) || !strnicmp(ptcKey, "DEL", 3)) + if (!strnicmp(ptcKey, "DELUID", 6)) { if (m_followers.empty()) return false; @@ -3533,6 +3545,28 @@ bool CChar::r_LoadVal( CScript & s ) return true; } + if (!strnicmp(ptcKey, "DELINDEX", 6)) + { + if (m_followers.empty()) + return false; + + const uint uiIndex = s.GetArgUVal(); + if (uiIndex >= m_followers.size()) + return false; + + CChar *pChar = m_followers[uiIndex].uid.CharFind(); + m_followers.erase(m_followers.begin() + uiIndex); + + if (!pChar) + { + g_Log.EventWarn("Follower with index %u is an invalid char! (Owner: 0%" PRIx32 ".)\n", uiIndex, GetUID().GetObjUID()); + return true; + } + + pChar->NPC_PetClearOwners(); + return true; + } + if (!strnicmp(ptcKey, "ADD", 3)) { int64 piCmd[2]; @@ -4163,10 +4197,14 @@ void CChar::r_Write( CScript & s ) s.WriteKeyVal("OFAME", GetFame() ); int iVal; - if ((iVal = Stat_GetMod(STAT_FOOD)) != 0) - s.WriteKeyVal("MODFOOD", iVal); + //if ((iVal = Stat_GetMod(STAT_FOOD)) != 0) + // s.WriteKeyVal("MODFOOD", iVal); if ((iVal = Stat_GetBase(STAT_FOOD)) != Char_GetDef()->m_MaxFood) s.WriteKeyVal("OFOOD", iVal); + if ((iVal = Stat_GetMaxMod(STAT_FOOD)) != 0) + s.WriteKeyVal("MODMAXFOOD", iVal); + if ((iVal = Stat_GetMax(STAT_FOOD)) != 0) + s.WriteKeyVal("MAXFOOD", iVal); s.WriteKeyVal("FOOD", Stat_GetVal(STAT_FOOD)); static constexpr lpctstr _ptcKeyModStat[STAT_BASE_QTY] = @@ -4182,7 +4220,7 @@ void CChar::r_Write( CScript & s ) "ODEX" }; - for (int j = 0; j < STAT_BASE_QTY; ++j) + for (int j = 0; j < STAT_BASE_QTY; ++j) { // this is VERY important, saving the MOD first if ((iVal = Stat_GetMod((STAT_TYPE)j)) != 0) diff --git a/src/game/chars/CChar.h b/src/game/chars/CChar.h index 20a4bd212..67580ceab 100644 --- a/src/game/chars/CChar.h +++ b/src/game/chars/CChar.h @@ -1019,7 +1019,7 @@ public: void StatFlag_Mod(uint64 uiStatFlag, bool fMod) noexcept; bool Spell_CastDone(); virtual bool OnSpellEffect( SPELL_TYPE spell, CChar * pCharSrc, int iSkillLevel, CItem * pSourceItem, bool fReflecting = false, int64 iDuration = 0) override; bool Spell_CanCast( SPELL_TYPE &spellRef, bool fTest, CObjBase * pSrc, bool fFailMsg, bool fCheckAntiMagic = true ); - CChar* Spell_Summon_Try(SPELL_TYPE spell, CPointMap ptTarg, CREID_TYPE uiCreature); + CChar* Spell_Summon_Try(SPELL_TYPE spell, CPointMap ptTarg, CREID_TYPE uiCreature, std::optional iFollowerSlotsOverride); int64 GetSpellDuration( SPELL_TYPE spell, int iSkillLevel, CChar * pCharSrc = nullptr ); // in tenths of second // Memories about objects in the world. ------------------- diff --git a/src/game/chars/CCharSpell.cpp b/src/game/chars/CCharSpell.cpp index f96cbefad..8e7d62f1f 100644 --- a/src/game/chars/CCharSpell.cpp +++ b/src/game/chars/CCharSpell.cpp @@ -2498,7 +2498,7 @@ bool CChar::Spell_CanCast( SPELL_TYPE &spellRef, bool fTest, CObjBase * pSrc, bo return true; } -CChar * CChar::Spell_Summon_Try(SPELL_TYPE spell, CPointMap ptTarg, CREID_TYPE uiCreature) +CChar * CChar::Spell_Summon_Try(SPELL_TYPE spell, CPointMap ptTarg, CREID_TYPE uiCreature, std::optional iFollowerSlotsOverride) { ADDTOCALLSTACK("CChar::Spell_CanSummon"); //Create the NPC and check if we can actually place it in the world, but do not place it yet. @@ -2618,7 +2618,7 @@ CChar * CChar::Spell_Summon_Try(SPELL_TYPE spell, CPointMap ptTarg, CREID_TYPE u if (IsSetOF(OF_PetSlots)) { - short iFollowerSlots = pChar->GetFollowerSlots(); + short iFollowerSlots = iFollowerSlotsOverride.has_value() ? iFollowerSlotsOverride.value() : pChar->GetFollowerSlots(); if (!FollowersUpdate(pChar, iFollowerSlots, true)) { SysMessageDefault(DEFMSG_PETSLOTS_TRY_SUMMON); @@ -2841,22 +2841,11 @@ bool CChar::Spell_CastDone() CObjBase * pObjSrc = m_Act_Prv_UID.ObjFind(); CChar* pSummon = nullptr; - ITEMID_TYPE iT1 = ITEMID_NOTHING; - ITEMID_TYPE iT2 = ITEMID_NOTHING; - CREID_TYPE iC1 = CREID_INVALID; - HUE_TYPE iColor = HUE_DEFAULT; - - uint fieldWidth = 0; - uint fieldGauge = 0; - uint areaRadius = 0; - SPELL_TYPE spell = m_atMagery.m_iSpell; const CSpellDef * pSpellDef = g_Cfg.GetSpellDef(spell); if (pSpellDef == nullptr) return false; - const bool fIsSpellField = pSpellDef->IsSpellType(SPELLFLAG_FIELD); - int iSkill, iDifficulty; if (!pSpellDef->GetPrimarySkill(&iSkill, &iDifficulty)) return false; @@ -2881,28 +2870,52 @@ bool CChar::Spell_CastDone() if ( (iSkill == SKILL_MYSTICISM) && (g_Cfg.m_iRacialFlags & RACIALF_GARG_MYSTICINSIGHT) && (iSkillLevel < 300) && IsGargoyle() ) iSkillLevel = 300; // Racial trait (Mystic Insight). Gargoyles always have a minimum of 30.0 Mysticism. - CScriptTriggerArgs Args(spell, iSkillLevel, pObjSrc); - Args.m_VarsLocal.SetNum("fieldWidth", 0); - Args.m_VarsLocal.SetNum("fieldGauge", 0); - Args.m_VarsLocal.SetNum("areaRadius", 0); - Args.m_VarsLocal.SetNum("duration", GetSpellDuration(spell, iSkillLevel, this), true); // tenths of second + const bool fIsSpellArea = pSpellDef->IsSpellType(SPELLFLAG_AREA); + const bool fIsSpellField = pSpellDef->IsSpellType(SPELLFLAG_FIELD); + const bool fIsSpellSummon = pSpellDef->IsSpellType(SPELLFLAG_SUMMON); + + HUE_TYPE uiColor = HUE_DEFAULT; + ITEMID_TYPE uiCreatedItemID_1 = ITEMID_NOTHING; + ITEMID_TYPE uiCreatedItemID_2 = ITEMID_NOTHING; + CREID_TYPE uiSummonedCreatureID = CREID_INVALID; + short iFollowerSlotsOverride = -1; + + uint uiFieldWidth = 0; + uint uiFieldGauge = 0; + uint uiAreaRadius = 0; + + CScriptTriggerArgs Args(spell, iSkillLevel, pObjSrc); + Args.m_VarsLocal.SetNum("Duration", GetSpellDuration(spell, iSkillLevel, this), true); // tenths of second + + if (fIsSpellArea) + { + Args.m_VarsLocal.SetNum("AreaRadius", 0); + } if (fIsSpellField) { + Args.m_VarsLocal.SetNum("FieldWidth", 0); + Args.m_VarsLocal.SetNum("FieldGauge", 0); + switch (spell) // Only setting ids and locals for field spells { - case SPELL_Wall_of_Stone: iT1 = ITEMID_STONE_WALL; iT2 = ITEMID_STONE_WALL; break; - case SPELL_Fire_Field: iT1 = ITEMID_FX_FIRE_F_EW; iT2 = ITEMID_FX_FIRE_F_NS; break; - case SPELL_Poison_Field: iT1 = ITEMID_FX_POISON_F_EW; iT2 = ITEMID_FX_POISON_F_NS; break; - case SPELL_Paralyze_Field: iT1 = ITEMID_FX_PARA_F_EW; iT2 = ITEMID_FX_PARA_F_NS; break; - case SPELL_Energy_Field: iT1 = ITEMID_FX_ENERGY_F_EW; iT2 = ITEMID_FX_ENERGY_F_NS; break; + case SPELL_Wall_of_Stone: uiCreatedItemID_1 = ITEMID_STONE_WALL; uiCreatedItemID_2 = ITEMID_STONE_WALL; break; + case SPELL_Fire_Field: uiCreatedItemID_1 = ITEMID_FX_FIRE_F_EW; uiCreatedItemID_2 = ITEMID_FX_FIRE_F_NS; break; + case SPELL_Poison_Field: uiCreatedItemID_1 = ITEMID_FX_POISON_F_EW; uiCreatedItemID_2 = ITEMID_FX_POISON_F_NS; break; + case SPELL_Paralyze_Field: uiCreatedItemID_1 = ITEMID_FX_PARA_F_EW; uiCreatedItemID_2 = ITEMID_FX_PARA_F_NS; break; + case SPELL_Energy_Field: uiCreatedItemID_1 = ITEMID_FX_ENERGY_F_EW; uiCreatedItemID_2 = ITEMID_FX_ENERGY_F_NS; break; default: break; } - Args.m_VarsLocal.SetNum("CreateObject1", iT1, false); - Args.m_VarsLocal.SetNum("CreateObject2", iT2, false); + Args.m_VarsLocal.SetNum("CreateObject1", uiCreatedItemID_1, false); + Args.m_VarsLocal.SetNum("CreateObject2", uiCreatedItemID_2, false); } + if (fIsSpellSummon) + { + Args.m_VarsLocal.SetNum("FollowerSlotsOverride", iFollowerSlotsOverride); + } + if (IsTrigUsed(TRIGGER_SPELLSUCCESS)) { if (OnTrigger(CTRIG_SpellSuccess, this, &Args) == TRIGRET_RET_TRUE) @@ -2925,58 +2938,67 @@ bool CChar::Spell_CastDone() //Setting new IDs as another variables to pass as different arguments to the field function. it1test = (ITEMID_TYPE)(ResGetIndex((dword)Args.m_VarsLocal.GetKeyNum("CreateObject1"))); it2test = (ITEMID_TYPE)(ResGetIndex((dword)Args.m_VarsLocal.GetKeyNum("CreateObject2"))); - fieldWidth = (uint)Args.m_VarsLocal.GetKeyNum("fieldWidth"); - fieldGauge = (uint)Args.m_VarsLocal.GetKeyNum("fieldGauge"); + uiFieldWidth = (uint)Args.m_VarsLocal.GetKeyNum("FieldWidth"); + uiFieldGauge = (uint)Args.m_VarsLocal.GetKeyNum("FieldGauge"); } - iC1 = (CREID_TYPE)(Args.m_VarsLocal.GetKeyNum("CreateObject1") & 0xFFFF); - areaRadius = (uint)Args.m_VarsLocal.GetKeyNum("areaRadius"); - int iDuration = (int)(Args.m_VarsLocal.GetKeyNum("duration")); - iDuration = maximum(0, iDuration); - iColor = (HUE_TYPE)(Args.m_VarsLocal.GetKeyNum("EffectColor")); + uiSummonedCreatureID = (CREID_TYPE)(Args.m_VarsLocal.GetKeyNum("CreateObject1") & 0xFFFF); + uiAreaRadius = (uint)Args.m_VarsLocal.GetKeyNum("AreaRadius"); + int iDuration = (int)(std::max((int64)0, Args.m_VarsLocal.GetKeyNum("Duration"))); + uiColor = (HUE_TYPE)(Args.m_VarsLocal.GetKeyNum("EffectColor")); - if (pSpellDef->IsSpellType(SPELLFLAG_SUMMON)) + if (fIsSpellSummon) { + iFollowerSlotsOverride = n64_narrow_n16(Args.m_VarsLocal.GetKeyNum("FollowerSlotsOverride")); + if (!pSpellDef->IsSpellType(SPELLFLAG_TARG_OBJ | SPELLFLAG_TARG_XYZ)) m_Act_p = GetTopPoint(); - pSummon = Spell_Summon_Try(spell, m_Act_p, iC1); + std::optional iMaybeOverride; + if (iFollowerSlotsOverride != -1) + iMaybeOverride = iFollowerSlotsOverride; + pSummon = Spell_Summon_Try(spell, m_Act_p, uiSummonedCreatureID, iMaybeOverride); if (!pSummon) { return false; } } + // Consume the reagents/mana/scroll/charge if (!Spell_CanCast(spell, false, pObjSrc, true)) + { + if (pSummon) + pSummon->Delete(true); return false; + } if (pSpellDef->IsSpellType(SPELLFLAG_SCRIPTED)) { - if (pSpellDef->IsSpellType(SPELLFLAG_SUMMON)) + if (fIsSpellSummon) { Spell_Summon_Place(pSummon, m_Act_p, iDuration); } else if (fIsSpellField) { - if (iT1 && iT2) + if (uiCreatedItemID_1 && uiCreatedItemID_2) { - if (!fieldWidth) - fieldWidth = 3; - if (!fieldGauge) - fieldGauge = 1; + if (!uiFieldWidth) + uiFieldWidth = 3; + if (!uiFieldGauge) + uiFieldGauge = 1; - Spell_Field(m_Act_p, iT1, iT2, fieldWidth, fieldGauge, iSkillLevel, this, it1test, it2test, iDuration, iColor); + Spell_Field(m_Act_p, uiCreatedItemID_1, uiCreatedItemID_2, uiFieldWidth, uiFieldGauge, iSkillLevel, this, it1test, it2test, iDuration, uiColor); } } - else if (pSpellDef->IsSpellType(SPELLFLAG_AREA)) + else if (fIsSpellArea) { - if (!areaRadius) - areaRadius = 4; + if (!uiAreaRadius) + uiAreaRadius = 4; if (!pSpellDef->IsSpellType(SPELLFLAG_TARG_OBJ | SPELLFLAG_TARG_XYZ)) - Spell_Area(GetTopPoint(), areaRadius, iSkillLevel, iDuration); + Spell_Area(GetTopPoint(), uiAreaRadius, iSkillLevel, iDuration); else - Spell_Area(m_Act_p, areaRadius, iSkillLevel, iDuration); + Spell_Area(m_Act_p, uiAreaRadius, iSkillLevel, iDuration); } else if (pSpellDef->IsSpellType(SPELLFLAG_POLY)) return false; @@ -2988,45 +3010,45 @@ bool CChar::Spell_CastDone() } else if (fIsSpellField) { - if (!fieldWidth) - fieldWidth = 3; - if (!fieldGauge) - fieldGauge = 1; + if (!uiFieldWidth) + uiFieldWidth = 3; + if (!uiFieldGauge) + uiFieldGauge = 1; - Spell_Field(m_Act_p, iT1, iT2, fieldWidth, fieldGauge, iSkillLevel, this, it1test, it2test, iDuration, iColor); + Spell_Field(m_Act_p, uiCreatedItemID_1, uiCreatedItemID_2, uiFieldWidth, uiFieldGauge, iSkillLevel, this, it1test, it2test, iDuration, uiColor); } - else if (pSpellDef->IsSpellType(SPELLFLAG_AREA)) + else if (fIsSpellArea) { - if (!areaRadius) + if (!uiAreaRadius) { switch (spell) { - case SPELL_Arch_Cure: areaRadius = 2; break; - case SPELL_Arch_Prot: areaRadius = 3; break; - case SPELL_Mass_Curse: areaRadius = 2; break; - case SPELL_Reveal: areaRadius = 1 + (iSkillLevel / 200); break; - case SPELL_Chain_Lightning: areaRadius = 2; break; - case SPELL_Mass_Dispel: areaRadius = 8; break; - case SPELL_Meteor_Swarm: areaRadius = 2; break; - case SPELL_Earthquake: areaRadius = 1 + (iSkillLevel / 150); break; - case SPELL_Poison_Strike: areaRadius = 2; break; - case SPELL_Wither: areaRadius = 4; break; - default: areaRadius = 4; break; + case SPELL_Arch_Cure: uiAreaRadius = 2; break; + case SPELL_Arch_Prot: uiAreaRadius = 3; break; + case SPELL_Mass_Curse: uiAreaRadius = 2; break; + case SPELL_Reveal: uiAreaRadius = 1 + (iSkillLevel / 200); break; + case SPELL_Chain_Lightning: uiAreaRadius = 2; break; + case SPELL_Mass_Dispel: uiAreaRadius = 8; break; + case SPELL_Meteor_Swarm: uiAreaRadius = 2; break; + case SPELL_Earthquake: uiAreaRadius = 1 + (iSkillLevel / 150); break; + case SPELL_Poison_Strike: uiAreaRadius = 2; break; + case SPELL_Wither: uiAreaRadius = 4; break; + default: uiAreaRadius = 4; break; } } if (!pSpellDef->IsSpellType(SPELLFLAG_TARG_OBJ | SPELLFLAG_TARG_XYZ)) - Spell_Area(GetTopPoint(), areaRadius, iSkillLevel, iDuration); + Spell_Area(GetTopPoint(), uiAreaRadius, iSkillLevel, iDuration); else - Spell_Area(m_Act_p, areaRadius, iSkillLevel, iDuration); + Spell_Area(m_Act_p, uiAreaRadius, iSkillLevel, iDuration); } - else if (pSpellDef->IsSpellType(SPELLFLAG_SUMMON)) + else if (fIsSpellSummon) { Spell_Summon_Place(pSummon, m_Act_p, iDuration); } else { - iT1 = it1test; // Set iT1 to it1test here because spell_field() needed both values to be passed. + uiCreatedItemID_1 = it1test; // Set iT1 to it1test here because spell_field() needed both values to be passed. switch (spell) { @@ -3035,7 +3057,7 @@ bool CChar::Spell_CastDone() case SPELL_Create_Food: { const CResourceID ridFoodDefault = g_Cfg.ResourceGetIDType(RES_ITEMDEF, "DEFFOOD"); - const ITEMID_TYPE idFood = ((iT1 > ITEMID_NOTHING) ? iT1 : (ITEMID_TYPE)(ridFoodDefault.GetResIndex())); + const ITEMID_TYPE idFood = ((uiCreatedItemID_1 > ITEMID_NOTHING) ? uiCreatedItemID_1 : (ITEMID_TYPE)(ridFoodDefault.GetResIndex())); CItem *pItem = CItem::CreateScript(idFood, this); ASSERT(pItem); if (pSpellDef->IsSpellType(SPELLFLAG_TARG_OBJ|SPELLFLAG_TARG_XYZ)) @@ -3112,12 +3134,12 @@ bool CChar::Spell_CastDone() case SPELL_Flame_Strike: { // Display spell. - if (!iT1) - iT1 = ITEMID_FX_FLAMESTRIKE; + if (!uiCreatedItemID_1) + uiCreatedItemID_1 = ITEMID_FX_FLAMESTRIKE; if (pObj == nullptr) { - EffectLocation(EFFECT_XYZ, iT1, nullptr, &m_Act_p, 20, 30); + EffectLocation(EFFECT_XYZ, uiCreatedItemID_1, nullptr, &m_Act_p, 20, 30); } else { From b75a9c949e2d77d27de1aa38387d029ff6240946 Mon Sep 17 00:00:00 2001 From: cbnolok Date: Thu, 3 Oct 2024 13:24:33 +0200 Subject: [PATCH 12/32] Refactoring and small additions to CompilerFlagsChecker.cmake. --- CMakeLists.txt | 15 +- cmake/CompilerFlagsChecker.cmake | 434 ++++++++++-------- cmake/toolchains/Windows-GNU-x86_64.cmake | 2 +- cmake/toolchains/Windows-MSVC.cmake | 7 +- .../include/Linux-Clang_common.inc.cmake | 4 +- .../include/Linux-GNU_common.inc.cmake | 4 +- .../include/OSX-AppleClang_common.inc.cmake | 4 +- .../include/Windows-Clang_common.inc.cmake | 4 +- .../include/Windows-GNU_common.inc.cmake | 4 +- lib/lib_build_flags_common_c.cmake | 9 +- src/common/sphere_library/CSString.h | 2 + 11 files changed, 268 insertions(+), 221 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 295f32bd4..9554694a9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,6 +4,10 @@ cmake_minimum_required(VERSION 3.24) set(CMAKE_SUPPRESS_REGENERATION TRUE) # Supress the ZERO_CHECK generation # -------------------- GUI checkboxes -------------------- +if(NOT MSVC) + set (CMAKE_BUILD_TYPE "Nightly" CACHE STRING "Which build type to build? Expected values: Debug, Nightly or Release.") +endif() + option( CMAKE_NO_GIT_REVISION "Do not try to retrieve the current git revision. Useful for building source not git-cloned from Github." @@ -35,7 +39,7 @@ option(USE_UBSAN "Enable Undefined Behavior Sanitizer." FALSE) option(USE_LSAN "Enable LeakSanitizer." FALSE) option(USE_MSAN "Enable MemorySanitizer." FALSE) -set(ENABLED_SANITIZER FALSE) +set(ENABLED_SANITIZER CACHE INTERNAL BOOL FALSE) if(USE_ASAN OR USE_MSAN OR USE_LSAN OR USE_MSAN) set(ENABLED_SANITIZER TRUE) endif() @@ -81,7 +85,7 @@ set(CMAKE_CXX_EXTENSIONS OFF) set(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "") set(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "") -# CMake also sets other predefined flags, which we don't want? +# In some cases, CMake also sets other predefined flags, which we don't want. #[[ set(CMAKE_C_FLAGS "") set(CMAKE_C_FLAGS_DEBUG "") @@ -98,6 +102,10 @@ set(CMAKE_EXE_LINKER_FLAGS_DEBUG "") set(CMAKE_EXE_LINKER_FLAGS_NIGHTLY "") set(CMAKE_EXE_LINKER_FLAGS_RELEASE "") ]] +# Example: using MSVC, /RTC1 is globally added (all projects) to DEBUG builds. It's mostly fine, except in some cases where we don't want it... +# We might want to delete only /RTC* flags, instead of erasing all of them altogether. +#STRING (REGEX REPLACE "/RTC(su|[1su])" "" CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}") +#STRING (REGEX REPLACE "/RTC(su|[1su])" "" CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG}") set(is_win32_app_linker) if(WIN32 AND NOT ${WIN32_SPAWN_CONSOLE}) @@ -136,7 +144,7 @@ if(SINGLE_TARGET) AND (NOT ${CMAKE_BUILD_TYPE} STREQUAL "Debug") AND (NOT ${CMAKE_BUILD_TYPE} STREQUAL "Nightly") ) - message(WARNING "Invalid parameter -DCMAKE_BUILD_TYPE, defaulting to Nightly.") + message(WARNING "Invalid parameter CMAKE_BUILD_TYPE (${CMAKE_BUILD_TYPE}), defaulting to Nightly.") # -> needed only for MAKEFILE-STYLE generators, which can't switch between different configs set(CMAKE_BUILD_TYPE "Nightly" CACHE STRING "" FORCE) else() @@ -250,7 +258,6 @@ message(STATUS) message(STATUS "Configuring external libraries...") add_subdirectory(lib) -message(STATUS) toolchain_exe_stuff() # stuff to be executed after ADD_EXECUTABLE # Get the Git revision number diff --git a/cmake/CompilerFlagsChecker.cmake b/cmake/CompilerFlagsChecker.cmake index 039af7d1e..2cd570296 100644 --- a/cmake/CompilerFlagsChecker.cmake +++ b/cmake/CompilerFlagsChecker.cmake @@ -14,7 +14,7 @@ if(NOT MSVC) -pipe -ffast-math ) - list(APPEND compiler_options_warning_base -Werror;-Wall;-Wextra;-Wpedantic) + list(APPEND base_compiler_options_warning -Werror;-Wall;-Wextra;-Wpedantic) # Compiler option flags. Common to both compilers, but older versions might not support the following. #check_cxx_compiler_flag("" COMP_HAS_) @@ -105,6 +105,15 @@ See comments in the toolchain and: https://github.com/google/sanitizers/wiki/Mem check_cxx_compiler_flag("-fPIE" COMP_HAS_F_PIE) endif() + if(ENABLED_SANITIZER) + if(RUNTIME_STATIC_LINK) + check_cxx_compiler_flag("-fstatic-libasan" COMP_HAS_F_STATIC_LIBASAN) + if(NOT COMP_HAS_F_STATIC_LIBASAN) + message(FATAL_ERROR "This compiler doesn't support statically linking libasan. Turn off RUNTIME_STATIC_LINK?") + endif() + endif() + endif() + if(USE_COMPILER_HARDENING_OPTIONS) message(STATUS "-- Compilation options (code hardening):") # Compiler option flags. Other sanitizers or code hardening. @@ -171,215 +180,232 @@ See comments in the toolchain and: https://github.com/google/sanitizers/wiki/Mem check_cxx_compiler_flag("-Wnested-anon-types" COMP_HAS_WNO_NESTED_ANON_TYPES) check_cxx_compiler_flag("-Wformat-security" COMP_HAS_WNO_FORMAT_SECURITY) # TODO: remove that when we'll have time to fix every printf format issue check_cxx_compiler_flag("-Wdeprecated-declarations" COMP_HAS_WNO_DEPRECATED_DECLARATIONS) + check_cxx_compiler_flag("-Wlanguage-extension-token" COMP_HAS_WNO_LANGUAGE_EXTENSION_TOKEN) #check_cxx_compiler_flag("-Wunknown-pragmas" COMP_HAS_) #check_cxx_compiler_flag("" COMP_HAS_) -else(NOT MSVC) + +elseif(MSVC) # Compiler warning flags (MSVC). message(STATUS "-- Compilation options (MSVC):") - check_cxx_compiler_flag("/Wd5105" COMP_HAS_DEFINE_MACRO_EXPANSION) # False positive warning, maybe even a MSVC bug. + check_cxx_compiler_flag("/W5105" COMP_HAS_W_DEFINE_MACRO_EXPANSION) # False positive warning, maybe even a MSVC bug. #check_cxx_compiler_flag("" COMP_HAS_) + endif() # ---- Append options into some lists. # ---- GCC/Clang -if(COMP_HAS_FNO_EXPENSIVE_OPTIMIZATIONS) - list(APPEND checked_compiler_options "-fno-expensive-optimizations") -endif() +if(NOT MSVC) + if(COMP_HAS_FNO_EXPENSIVE_OPTIMIZATIONS) + list(APPEND checked_compiler_options "-fno-expensive-optimizations") + endif() -if(COMP_HAS_ASAN) - list(APPEND checked_compiler_options_asan "-fsanitize=address") - list(APPEND checked_linker_options_all "-fsanitize=address") - if(RUNTIME_STATIC_LINK) - list(APPEND checked_linker_options_all "-static-libasan") + if(COMP_HAS_ASAN) + list(APPEND checked_compiler_options_asan "-fsanitize=address") + list(APPEND checked_linker_options_all "-fsanitize=address") + if(COMP_HAS_F_STATIC_LIBASAN) + list(APPEND checked_linker_options_all "-static-libasan") + endif() + if(COMP_HAS_FSAN_CFI) + list(APPEND checked_compiler_options_asan "-fsanitize-cfi") + endif() + if(COMP_HAS_FSAN_ADDRESS_USE_AFTER_SCOPE) + list(APPEND checked_compiler_options_asan "-fsanitize-address-use-after-scope") + endif() + if(COMP_HAS_FSAN_PTR_COMP) + list(APPEND checked_compiler_options_asan "-fsanitize=pointer-compare") + endif() + if(COMP_HAS_FSAN_PTR_SUB) + list(APPEND checked_compiler_options_asan "-fsanitize=pointer-subtract") + endif() + if(COMP_HAS_FSAN_TRAP_ALL) + list(APPEND checked_compiler_options_asan "-fsanitize-trap=all") + endif() endif() - if(COMP_HAS_FSAN_CFI) - list(APPEND checked_compiler_options_asan "-fsanitize-cfi") + + if(COMP_HAS_UBSAN) + list(APPEND checked_compiler_options_ubsan "-fsanitize=undefined") + list(APPEND checked_linker_options_all "-fsanitize=undefined") + if(RUNTIME_STATIC_LINK) + list(APPEND checked_linker_options_all "-static-libubsan") + endif() + if(COMP_HAS_FSAN_FLOAT_DIVIDE_BY_ZERO) + list(APPEND checked_compiler_options_ubsan "-fsanitize=float-divide-by-zero") + endif() + if(COMP_HAS_FSAN_UNSIGNED_INTEGER_OVERFLOW) + list(APPEND checked_compiler_options_ubsan "-fsanitize=unsigned-integer-overflow") + endif() + if(COMP_HAS_FSAN_IMPLICIT_CONVERSION) + list(APPEND checked_compiler_options_ubsan "-fsanitize=implicit-conversion") + endif() + if(COMP_HAS_FSAN_NO_ENUM) + list(APPEND checked_compiler_options_ubsan "-fno-sanitize=enum") + endif() + if(COMP_HAS_FSAN_LOCAL_BOUNDS) + list(APPEND checked_compiler_options_ubsan "-fsanitize=local-bounds") + endif() endif() - if(COMP_HAS_FSAN_ADDRESS_USE_AFTER_SCOPE) - list(APPEND checked_compiler_options_asan "-fsanitize-address-use-after-scope") + + if(COMP_HAS_LSAN) + list(APPEND checked_compiler_options_lsan "-fsanitize=leak") + list(APPEND checked_linker_options_all "-fsanitize=leak") + if(RUNTIME_STATIC_LINK) + list(APPEND checked_linker_options_all "-static-liblsan") + endif() endif() - if(COMP_HAS_FSAN_PTR_COMP) - list(APPEND checked_compiler_options_asan "-fsanitize=pointer-compare") + + if(COMP_HAS_MSAN) + list(APPEND checked_compiler_options_msan "-fsanitize=memory") + list(APPEND checked_linker_options_all "-fsanitize=memory") + if(RUNTIME_STATIC_LINK) + list(APPEND checked_linker_options_all "-static-libmsan") + endif() + if(COMP_HAS_F_SANITIZE_MEMORY_TRACK_ORIGINS) + list(APPEND checked_compiler_options_msan "-fsanitize=memory-track-origins") + endif() + if(COMP_HAS_F_PIE) + list(APPEND checked_compiler_options_msan "-fPIE") + list(APPEND checked_linker_options_all "-pie") + endif() endif() - if(COMP_HAS_FSAN_PTR_SUB) - list(APPEND checked_compiler_options_asan "-fsanitize=pointer-subtract") + + if(COMP_HAS_F_SANITIZE_SAFE_STACK) + list(APPEND checked_compiler_options_sanitize_harden "-fsanitize=safe-stack") endif() - if(COMP_HAS_FSAN_TRAP_ALL) - list(APPEND checked_compiler_options_asan "-fsanitize-trap=all") + if(COMP_HAS_FCF_PROTECTION_FULL) + list(APPEND checked_compiler_options_sanitize_harden "-fcf-protection=full") endif() -endif() - -if(COMP_HAS_UBSAN) - list(APPEND checked_compiler_options_ubsan "-fsanitize=undefined") - list(APPEND checked_linker_options_all "-fsanitize=undefined") - if(RUNTIME_STATIC_LINK) - list(APPEND checked_linker_options_all "-static-libubsan") + if(COMP_HAS_F_STACK_CHECK) + list(APPEND checked_compiler_options_sanitize_harden "-fstack-check") endif() - if(COMP_HAS_FSAN_FLOAT_DIVIDE_BY_ZERO) - list(APPEND checked_compiler_options_ubsan "-fsanitize=float-divide-by-zero") + if(COMP_HAS_F_STACK_PROTECTOR_ALL) + list(APPEND checked_compiler_options_sanitize_harden "-fstack-protector-all") + elseif(COMP_HAS_F_STACK_PROTECTOR_STRONG) + list(APPEND checked_compiler_options_sanitize_harden "-fstack-protector-strong") + elseif(COMP_HAS_F_STACK_PROTECTOR) + list(APPEND checked_compiler_options_sanitize_harden "-fstack-protector") endif() - if(COMP_HAS_FSAN_UNSIGNED_INTEGER_OVERFLOW) - list(APPEND checked_compiler_options_ubsan "-fsanitize=unsigned-integer-overflow") + if(COMP_HAS_F_STACK_CLASH_PROTECTION) + list(APPEND checked_compiler_options_sanitize_harden "-fstack-clash-protection") endif() - if(COMP_HAS_FSAN_IMPLICIT_CONVERSION) - list(APPEND checked_compiler_options_ubsan "-fsanitize=implicit-conversion") + if(COMP_HAS_F_VTABLE_VERIFY_PREINIT) + list(APPEND checked_compiler_options_sanitize_harden "-fvtable-verify=preinit") endif() - if(COMP_HAS_FSAN_NO_ENUM) - list(APPEND checked_compiler_options_ubsan "-fno-sanitize=enum") + if(COMP_HAS_F_HARDEN_CFR) + list(APPEND checked_compiler_options_sanitize_harden "-fharden-control-flow-redundancy") endif() - if(COMP_HAS_FSAN_LOCAL_BOUNDS) - list(APPEND checked_compiler_options_ubsan "-fsanitize=local-bounds") + if(COMP_HAS_F_HARDCFR_CHECK_EXCEPTIONS) + list(APPEND checked_compiler_options_sanitize_harden "-fhardcfr-check-exceptions") endif() -endif() -if(COMP_HAS_LSAN) - list(APPEND checked_compiler_options_lsan "-fsanitize=leak") - list(APPEND checked_linker_options_all "-fsanitize=leak") - if(RUNTIME_STATIC_LINK) - list(APPEND checked_linker_options_all "-static-liblsan") + if(COMP_HAS_W_USELESS_CAST) + list(APPEND checked_compiler_warnings "-Wuseless-cast") endif() -endif() - -if(COMP_HAS_MSAN) - list(APPEND checked_compiler_options_msan "-fsanitize=memory") - list(APPEND checked_linker_options_all "-fsanitize=memory") - if(RUNTIME_STATIC_LINK) - list(APPEND checked_linker_options_all "-static-libmsan") + if(COMP_HAS_NULL_DEREFERENCE) + list(APPEND checked_compiler_warnings "-Wnull-dereference") endif() - if(COMP_HAS_F_SANITIZE_MEMORY_TRACK_ORIGINS) - list(APPEND checked_compiler_options_msan "-fsanitize=memory-track-origins") + if(COMP_HAS_W_CONVERSION) + list(APPEND checked_compiler_warnings "-Wconversion") endif() - if(COMP_HAS_F_PIE) - list(APPEND checked_compiler_options_msan "-fPIE") - list(APPEND checked_linker_options_all "-pie") + if(COMP_HAS_W_CAST_QUAL) + list(APPEND checked_compiler_warnings "-Wcast-qual") + endif() + if(COMP_HAS_W_ZERO_NULLPTR) + list(APPEND checked_compiler_warnings "-Wzero-as-null-pointer-constant") + endif() + if(COMP_HAS_W_DISABLE_OPT) + list(APPEND checked_compiler_warnings "-Wdisabled-optimization") + endif() + if(COMP_HAS_W_INVALID_PCH) + list(APPEND checked_compiler_warnings "-Winvalid-pch") + endif() + if(COMP_HAS_W_SHADOW) + list(APPEND checked_compiler_warnings "-Wshadow") endif() -endif() -if(COMP_HAS_F_SANITIZE_SAFE_STACK) - list(APPEND checked_compiler_options_sanitize_harden "-fsanitize=safe-stack") -endif() -if(COMP_HAS_FCF_PROTECTION_FULL) - list(APPEND checked_compiler_options_sanitize_harden "-fcf-protection=full") -endif() -if(COMP_HAS_F_STACK_CHECK) - list(APPEND checked_compiler_options_sanitize_harden "-fstack-check") -endif() -if(COMP_HAS_F_STACK_PROTECTOR_ALL) - list(APPEND checked_compiler_options_sanitize_harden "-fstack-protector-all") -elseif(COMP_HAS_F_STACK_PROTECTOR_STRONG) - list(APPEND checked_compiler_options_sanitize_harden "-fstack-protector-strong") -elseif(COMP_HAS_F_STACK_PROTECTOR) - list(APPEND checked_compiler_options_sanitize_harden "-fstack-protector") -endif() -if(COMP_HAS_F_STACK_CLASH_PROTECTION) - list(APPEND checked_compiler_options_sanitize_harden "-fstack-clash-protection") -endif() -if(COMP_HAS_F_VTABLE_VERIFY_PREINIT) - list(APPEND checked_compiler_options_sanitize_harden "-fvtable-verify=preinit") -endif() -if(COMP_HAS_F_HARDEN_CFR) - list(APPEND checked_compiler_options_sanitize_harden "-fharden-control-flow-redundancy") -endif() -if(COMP_HAS_F_HARDCFR_CHECK_EXCEPTIONS) - list(APPEND checked_compiler_options_sanitize_harden "-fhardcfr-check-exceptions") -endif() + if(COMP_HAS_W_LTO_TYPE_MISMATCH) + list(APPEND checked_compiler_warnings "-Wlto-type-mismatch") + endif() + if(COMP_HAS_W_SHIFT_OVERFLOW) + list(APPEND checked_compiler_warnings "-Wshift-overflow=2") + endif() + if(COMP_HAS_W_DUPLICATED_COND) + list(APPEND checked_compiler_warnings "-Wduplicated-cond") + endif() + if(COMP_HAS_W_SIZED_DEALLOC) + list(APPEND checked_compiler_warnings "-Wsized-deallocation") + endif() + if(COMP_HAS_W_VECTOR_OP_PERF) + list(APPEND checked_compiler_warnings "-Wvector-operation-performance") + endif() + if(COMP_HAS_W_TRAMPOLINES) + list(APPEND checked_compiler_warnings "-Wtrampolines") + endif() + if(COMP_HAS_W_WEAK_VTABLES) + list(APPEND checked_compiler_warnings "-Wweak-vtables") + endif() + if(COMP_HAS_W_MISSING_PROTOTYPES) + list(APPEND checked_compiler_warnings "-Wmissing-prototypes") + endif() + if(COMP_HAS_W_MISSING_VARIABLE_DECL) + list(APPEND checked_compiler_warnings "-Wmissing-variable-declarations") + endif() -if(COMP_HAS_W_USELESS_CAST) - list(APPEND checked_compiler_warnings "-Wuseless-cast") -endif() -if(COMP_HAS_NULL_DEREFERENCE) - list(APPEND checked_compiler_warnings "-Wnull-dereference") -endif() -if(COMP_HAS_W_CONVERSION) - list(APPEND checked_compiler_warnings "-Wconversion") -endif() -if(COMP_HAS_W_CAST_QUAL) - list(APPEND checked_compiler_warnings "-Wcast-qual") -endif() -if(COMP_HAS_W_ZERO_NULLPTR) - list(APPEND checked_compiler_warnings "-Wzero-as-null-pointer-constant") -endif() -if(COMP_HAS_W_DISABLE_OPT) - list(APPEND checked_compiler_warnings "-Wdisabled-optimization") -endif() -if(COMP_HAS_W_INVALID_PCH) - list(APPEND checked_compiler_warnings "-Winvalid-pch") -endif() -if(COMP_HAS_W_SHADOW) - list(APPEND checked_compiler_warnings "-Wshadow") + if(COMP_HAS_WNO_UNUSED_FUNCTION) + list(APPEND checked_compiler_warnings_disabled "-Wno-unused-function") + endif() + if(COMP_HAS_WNO_FORMAT_NONLITERAL) + list(APPEND checked_compiler_warnings_disabled "-Wno-format-nonliteral") + endif() + if(COMP_HAS_WNO_NONNULL_COMPARE) + list(APPEND checked_compiler_warnings_disabled "-Wno-nonnull-compare") + endif() + if(COMP_HAS_WNO_MAYBE_UNINIT) + list(APPEND checked_compiler_warnings_disabled "-Wno-maybe-uninitialized") + endif() + if(COMP_HAS_WNO_SWITCH) + list(APPEND checked_compiler_warnings_disabled "-Wno-switch") + endif() + if(COMP_HAS_WNO_IMPLICIT_FALLTHROUGH) + list(APPEND checked_compiler_warnings_disabled "-Wno-implicit-fallthrough") + endif() + if(COMP_HAS_WNO_PARENTHESES) + list(APPEND checked_compiler_warnings_disabled "-Wno-parentheses") + endif() + if(COMP_HAS_WNO_MISLEADING_INDENTATION) + list(APPEND checked_compiler_warnings_disabled "-Wno-misleading-indentation") + endif() + if(COMP_HAS_WNO_UNUSED_RESULT) + list(APPEND checked_compiler_warnings_disabled "-Wno-unused-result") + endif() + if(COMP_HAS_WNO_NESTED_ANON_TYPES) + list(APPEND checked_compiler_warnings_disabled "-Wno-nested-anon-types") + endif() + if(COMP_HAS_WNO_FORMAT_SECURITY) + list(APPEND checked_compiler_warnings_disabled "-Wno-format-security") + endif() + if(COMP_HAS_WNO_DEPRECATED_DECLARATIONS) + list(APPEND checked_compiler_warnings_disabled "-Wno-deprecated-declarations") + endif() + if(COMP_HAS_WNO_LANGUAGE_EXTENSION_TOKEN) + list(APPEND checked_compiler_warnings_disabled "-Wno-language-extension-token") + endif() endif() -if(COMP_HAS_W_LTO_TYPE_MISMATCH) - list(APPEND checked_compiler_warnings "-Wlto-type-mismatch") -endif() -if(COMP_HAS_W_SHIFT_OVERFLOW) - list(APPEND checked_compiler_warnings "-Wshift-overflow=2") -endif() -if(COMP_HAS_W_DUPLICATED_COND) - list(APPEND checked_compiler_warnings "-Wduplicated-cond") -endif() -if(COMP_HAS_W_SIZED_DEALLOC) - list(APPEND checked_compiler_warnings "-Wsized-deallocation") -endif() -if(COMP_HAS_W_VECTOR_OP_PERF) - list(APPEND checked_compiler_warnings "-Wvector-operation-performance") -endif() -if(COMP_HAS_W_TRAMPOLINES) - list(APPEND checked_compiler_warnings "-Wtrampolines") -endif() -if(COMP_HAS_W_WEAK_VTABLES) - list(APPEND checked_compiler_warnings "-Wweak-vtables") -endif() -if(COMP_HAS_W_MISSING_PROTOTYPES) - list(APPEND checked_compiler_warnings "-Wmissing-prototypes") -endif() -if(COMP_HAS_W_MISSING_VARIABLE_DECL) - list(APPEND checked_compiler_warnings "-Wmissing-variable-declarations") -endif() +# ---- MSVC -if(COMP_HAS_WNO_UNUSED_FUNCTION) - list(APPEND checked_compiler_warnings_disabled "-Wno-unused-function") -endif() -if(COMP_HAS_WNO_FORMAT_NONLITERAL) - list(APPEND checked_compiler_warnings_disabled "-Wno-format-nonliteral") -endif() -if(COMP_HAS_WNO_NONNULL_COMPARE) - list(APPEND checked_compiler_warnings_disabled "-Wno-nonnull-compare") -endif() -if(COMP_HAS_WNO_MAYBE_UNINIT) - list(APPEND checked_compiler_warnings_disabled "-Wno-maybe-uninitialized") -endif() -if(COMP_HAS_WNO_SWITCH) - list(APPEND checked_compiler_warnings_disabled "-Wno-switch") -endif() -if(COMP_HAS_WNO_IMPLICIT_FALLTHROUGH) - list(APPEND checked_compiler_warnings_disabled "-Wno-implicit-fallthrough") -endif() -if(COMP_HAS_WNO_PARENTHESES) - list(APPEND checked_compiler_warnings_disabled "-Wno-parentheses") -endif() -if(COMP_HAS_WNO_MISLEADING_INDENTATION) - list(APPEND checked_compiler_warnings_disabled "-Wno-misleading-indentation") -endif() -if(COMP_HAS_WNO_UNUSED_RESULT) - list(APPEND checked_compiler_warnings_disabled "-Wno-unused-result") -endif() -if(COMP_HAS_WNO_NESTED_ANON_TYPES) - list(APPEND checked_compiler_warnings_disabled "-Wno-nested-anon-types") -endif() -if(COMP_HAS_WNO_FORMAT_SECURITY) - list(APPEND checked_compiler_warnings_disabled "-Wno-format-security") -endif() -if(COMP_HAS_WNO_DEPRECATED_DECLARATIONS) - list(APPEND checked_compiler_warnings_disabled "-Wno-deprecated-declarations") -endif() +if(MSVC) + #list( + # APPEND + # base_compiler_options_msvc + # "/wd5105" + #) -# ---- MSVC + if(COMP_HAS_W_DEFINE_MACRO_EXPANSION) + list(APPEND checked_compiler_options_msvc "/wd5105") + endif() -if(COMP_HAS_DEFINE_MACRO_EXPANSION) - list(APPEND checked_compiler_options_msvc "/Wd5105") endif() # ---- Double checks @@ -408,34 +434,35 @@ set(checked_compiler_options_msvc) ## ---- -list( - APPEND - list_gnu_explicit_compiler_options_all - ${compiler_options_base} - ${compiler_options_warning_base} - ${checked_compiler_options} - ${checked_compiler_options_asan} - ${checked_compiler_options_ubsan} - ${checked_compiler_options_lsan} - ${checked_compiler_options_msan} - ${checked_compiler_options_sanitize_harden} - ${checked_compiler_warnings} - ${checked_compiler_warnings_disabled} - ${checked_compiler_options_msvc} -) +# Now sum up, report and encapsulate all the options. -list(APPEND list_gnu_explicit_linker_options_all ${checked_linker_options_all};-pthread;-dynamic;-Wl,--fatal-warnings) +if(NOT MSVC) + list( + APPEND + list_explicit_compiler_options_all + ${compiler_options_base} + ${base_compiler_options_warning} + ${checked_compiler_options} + ${checked_compiler_options_asan} + ${checked_compiler_options_ubsan} + ${checked_compiler_options_lsan} + ${checked_compiler_options_msan} + ${checked_compiler_options_sanitize_harden} + ${checked_compiler_warnings} + ${checked_compiler_warnings_disabled} + ) -#string(JOIN " " string_checked_compiler_options_all ${list_checked_compiler_options_all}) -#set(string_checked_compiler_options_all CACHE STRING "Additional compiler flags, dynamically added." FORCE) -set(list_gnu_explicit_compiler_options_all CACHE STRING "Additional compiler flags, dynamically added." FORCE) -set(list_gnu_explicit_linker_options_all CACHE STRING "Additional linker flags, dynamically added." FORCE) + list(APPEND list_explicit_linker_options_all ${checked_linker_options_all};-pthread;-dynamic;-Wl,--fatal-warnings) -## ---- + #string(JOIN " " string_checked_compiler_options_all ${list_checked_compiler_options_all}) + #set(string_checked_compiler_options_all CACHE INTERNAL STRING) + set(list_explicit_compiler_options_all CACHE INTERNAL STRING) + set(list_explicit_linker_options_all CACHE INTERNAL STRING) + + # -- -if(NOT MSVC) message(STATUS "Adding the following base compiler options: ${compiler_options_base}") - message(STATUS "Adding the following base compiler warning options: ${compiler_options_warning_base}") + message(STATUS "Adding the following base compiler warning options: ${base_compiler_options_warning}") message(STATUS "Adding the following conditional compiler options: ${checked_compiler_options}.") if(COMP_HAS_ASAN) @@ -464,7 +491,16 @@ if(NOT MSVC) STATUS "Adding the following conditional compiler warnings ignore options: ${checked_compiler_warnings_disabled}." ) - message(STATUS "Adding the following linker options: ${list_gnu_explicit_linker_options_all}.") + message(STATUS "Adding the following linker options: ${list_explicit_linker_options_all}.") + elseif(MSVC) - message(STATUS "Adding the following conditional compiler options: ${checked_compiler_options_msvc}.") + list( + APPEND + list_explicit_compiler_options_all + ${base_compiler_options_msvc} + ${checked_compiler_options_msvc} + ) + + message(STATUS "Adding the following conditional compiler options: ${list_explicit_compiler_options_all}.") + endif() diff --git a/cmake/toolchains/Windows-GNU-x86_64.cmake b/cmake/toolchains/Windows-GNU-x86_64.cmake index 00b1fafc1..ec6ac7494 100644 --- a/cmake/toolchains/Windows-GNU-x86_64.cmake +++ b/cmake/toolchains/Windows-GNU-x86_64.cmake @@ -17,7 +17,7 @@ function(toolchain_after_project) # Do not set CMAKE_SYSTEM_NAME if compiling for the same OS, otherwise CMAKE_CROSSCOMPILING will be set to TRUE #unset(CMAKE_SYSTEM_NAME) #SET(CMAKE_SYSTEM_NAME "Windows" CACHE INTERNAL "" FORCE) - unset() + unset(CMAKE_SYSTEM_PROCESSOR) set(CMAKE_SYSTEM_PROCESSOR "x86_64" CACHE INTERNAL "" FORCE) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin-x86_64" PARENT_SCOPE) #set(ARCH_BITS 64 CACHE INTERNAL "" FORCE) # automatically gotten from CMAKE_SYSTEM_PROCESSOR diff --git a/cmake/toolchains/Windows-MSVC.cmake b/cmake/toolchains/Windows-MSVC.cmake index 3088faee3..3994a6e7f 100644 --- a/cmake/toolchains/Windows-MSVC.cmake +++ b/cmake/toolchains/Windows-MSVC.cmake @@ -42,7 +42,7 @@ function(toolchain_exe_stuff) endif() #-- Validate sanitizers options and store them between the common compiler flags. - + # TODO: move sanitizers checks to CompilerFlagsChecker.cmake. set(ENABLED_SANITIZER false) if(${USE_ASAN}) if(${MSVC_TOOLSET_VERSION} LESS_EQUAL 141) # VS 2017 @@ -74,6 +74,7 @@ function(toolchain_exe_stuff) set(cxx_compiler_flags_common ${CXX_FLAGS_EXTRA} + ${list_explicit_compiler_options_all} /W4 /MP /GR @@ -126,10 +127,10 @@ function(toolchain_exe_stuff) # gersemi: off target_link_options(spheresvr PRIVATE - /WX # treat all warnings as errors + /WX # treat all warnings as errors $<$: ${EXE_LINKER_EXTRA} /NODEFAULTLIB:libcmtd /OPT:REF,ICF /LTCG /INCREMENTAL:NO> $<$: ${EXE_LINKER_EXTRA} /NODEFAULTLIB:libcmtd /OPT:REF,ICF /LTCG /INCREMENTAL:NO> - $<$: ${EXE_LINKER_EXTRA} /NODEFAULTLIB:libcmt /SAFESEH:NO /DEBUG /LTCG:OFF + $<$: ${EXE_LINKER_EXTRA} /NODEFAULTLIB:libcmt /SAFESEH:NO /DEBUG /LTCG:OFF $,/INCREMENTAL:NO /EDITANDCONTINUE:NO,/INCREMENTAL /EDITANDCONTINUE> > ) # gersemi: on diff --git a/cmake/toolchains/include/Linux-Clang_common.inc.cmake b/cmake/toolchains/include/Linux-Clang_common.inc.cmake index b7493dc50..a7304c79c 100644 --- a/cmake/toolchains/include/Linux-Clang_common.inc.cmake +++ b/cmake/toolchains/include/Linux-Clang_common.inc.cmake @@ -22,7 +22,7 @@ function(toolchain_exe_stuff_common) #string(REPLACE ";" " " CXX_FLAGS_EXTRA "${CXX_FLAGS_EXTRA}") - set(cxx_compiler_options_common ${list_gnu_explicit_compiler_options_all} ${CXX_FLAGS_EXTRA}) + set(cxx_compiler_options_common ${list_explicit_compiler_options_all} ${CXX_FLAGS_EXTRA}) #separate_arguments(cxx_compiler_options_common) #-- Apply compiler flags, only the ones specific per build type. @@ -55,7 +55,7 @@ function(toolchain_exe_stuff_common) #-- Store common linker flags. set(cxx_linker_options_common - ${list_gnu_explicit_linker_options_all} + ${list_explicit_linker_options_all} ${CMAKE_EXE_LINKER_FLAGS_EXTRA} $<$: -static-libstdc++ diff --git a/cmake/toolchains/include/Linux-GNU_common.inc.cmake b/cmake/toolchains/include/Linux-GNU_common.inc.cmake index ce705b3a6..19e8c3a71 100644 --- a/cmake/toolchains/include/Linux-GNU_common.inc.cmake +++ b/cmake/toolchains/include/Linux-GNU_common.inc.cmake @@ -17,7 +17,7 @@ function(toolchain_exe_stuff_common) #-- Store compiler flags common to all builds. - set(cxx_compiler_options_common ${list_gnu_explicit_compiler_options_all} ${CXX_FLAGS_EXTRA}) + set(cxx_compiler_options_common ${list_explicit_compiler_options_all} ${CXX_FLAGS_EXTRA}) #-- Apply compiler flags, only the ones specific per build type. @@ -43,7 +43,7 @@ function(toolchain_exe_stuff_common) #-- Store common linker flags. set(cxx_linker_options_common - ${list_gnu_explicit_linker_options_all} + ${list_explicit_linker_options_all} ${CMAKE_EXE_LINKER_FLAGS_EXTRA} $<$: -static-libstdc++ diff --git a/cmake/toolchains/include/OSX-AppleClang_common.inc.cmake b/cmake/toolchains/include/OSX-AppleClang_common.inc.cmake index fb877cffe..699b50881 100644 --- a/cmake/toolchains/include/OSX-AppleClang_common.inc.cmake +++ b/cmake/toolchains/include/OSX-AppleClang_common.inc.cmake @@ -24,7 +24,7 @@ function(toolchain_exe_stuff_common) #-- Store compiler flags common to all builds. - set(cxx_compiler_options_common ${list_gnu_explicit_compiler_options_all} ${cxx_local_opts} ${CXX_FLAGS_EXTRA}) + set(cxx_compiler_options_common ${list_explicit_compiler_options_all} ${cxx_local_opts} ${CXX_FLAGS_EXTRA}) #-- Apply compiler flags, only the ones specific per build type. @@ -50,7 +50,7 @@ function(toolchain_exe_stuff_common) #-- Store common linker flags. set(cxx_linker_options_common - ${list_gnu_explicit_linker_options_all} + ${list_explicit_linker_options_all} ${CMAKE_EXE_LINKER_FLAGS_EXTRA} $<$: -static-libstdc++ diff --git a/cmake/toolchains/include/Windows-Clang_common.inc.cmake b/cmake/toolchains/include/Windows-Clang_common.inc.cmake index 7e7f9f30c..a01a37d09 100644 --- a/cmake/toolchains/include/Windows-Clang_common.inc.cmake +++ b/cmake/toolchains/include/Windows-Clang_common.inc.cmake @@ -31,7 +31,7 @@ function(toolchain_exe_stuff_common) # -mno-ms-bitfields is needed to fix structure packing; # -pthread unused here? we only need to specify that to the linker? ) - set(cxx_compiler_options_common ${list_gnu_explicit_compiler_options_all} ${cxx_local_opts} ${CXX_FLAGS_EXTRA}) + set(cxx_compiler_options_common ${list_explicit_compiler_options_all} ${cxx_local_opts} ${CXX_FLAGS_EXTRA}) #-- Apply compiler flags, only the ones specific per build type. @@ -91,7 +91,7 @@ function(toolchain_exe_stuff_common) set(cxx_linker_options_common ${CMAKE_EXE_LINKER_FLAGS_EXTRA}) if(${CLANG_USE_GCC_LINKER}) - set(cxx_linker_options_common ${list_gnu_explicit_linker_options_all}) + set(cxx_linker_options_common ${list_explicit_linker_options_all}) if(${RUNTIME_STATIC_LINK}) set(cxx_linker_options_common ${cxx_linker_options_common} -static-libstdc++ -static-libgcc) # no way to statically link against libc? maybe we can on windows? endif() diff --git a/cmake/toolchains/include/Windows-GNU_common.inc.cmake b/cmake/toolchains/include/Windows-GNU_common.inc.cmake index 58f2866df..0dfdb2968 100644 --- a/cmake/toolchains/include/Windows-GNU_common.inc.cmake +++ b/cmake/toolchains/include/Windows-GNU_common.inc.cmake @@ -20,7 +20,7 @@ function(toolchain_exe_stuff_common) -mno-ms-bitfields # it's needed to fix structure packing ) - set(cxx_compiler_options_common ${list_gnu_explicit_compiler_options_all} ${cxx_local_opts} ${CXX_FLAGS_EXTRA}) + set(cxx_compiler_options_common ${list_explicit_compiler_options_all} ${cxx_local_opts} ${CXX_FLAGS_EXTRA}) #-- Apply compiler flags, only the ones specific per build type. @@ -46,7 +46,7 @@ function(toolchain_exe_stuff_common) #-- Store common linker flags. set(cxx_linker_options_common - ${list_gnu_explicit_linker_options_all} + ${list_explicit_linker_options_all} ${CMAKE_EXE_LINKER_FLAGS_EXTRA} $<$: -static-libstdc++ diff --git a/lib/lib_build_flags_common_c.cmake b/lib/lib_build_flags_common_c.cmake index d34668325..2d3cc4734 100644 --- a/lib/lib_build_flags_common_c.cmake +++ b/lib/lib_build_flags_common_c.cmake @@ -6,9 +6,9 @@ endif() if(MSVC) # gersemi: off set (c_compiler_options_common - /O2 /EHsc /GA /Gw /Gy /GF /GR- /GS- - $<$: $,/MT,/MD> $<$:/Zi>> - $<$: $,/MT,/MD> $<$:/Zi>> + /EHsc /GA /Gw /Gy /GF /GR- /GS- + $<$: $,/MT,/MD> $,/O1 /Zi,/O2>> + $<$: $,/MT,/MD> $,/O1 /Zi,/O2>> $<$: $,/MTd,/MDd> $,/Zi,/ZI>> ) set (c_linker_options_common @@ -17,7 +17,8 @@ if(MSVC) $<$: /DEBUG /LTCG:OFF /NODEFAULTLIB:libcmt> ) # gersemi: on -else(MSVC) + +elseif(NOT MSVC) set(c_compiler_options_common -pipe -fexceptions diff --git a/src/common/sphere_library/CSString.h b/src/common/sphere_library/CSString.h index ecd7737b4..5537b4015 100644 --- a/src/common/sphere_library/CSString.h +++ b/src/common/sphere_library/CSString.h @@ -6,11 +6,13 @@ #ifndef _INC_CSSTRING_H #define _INC_CSSTRING_H +#include "../common.h" #ifdef __MINGW32__ #include #endif // __MINGW32__ #include // needed for va_list + /** * @brief Custom String implementation. */ From d69dda599ad4c71aab7bcfbc8c65b873ed007149 Mon Sep 17 00:00:00 2001 From: cbnolok Date: Thu, 3 Oct 2024 13:27:02 +0200 Subject: [PATCH 13/32] stypecast.h: split checked casts, one variant using ASSERT, another just printing a warning message. --- src/CMakeSources.cmake | 3 +- src/common/sphere_library/stypecast.cpp | 11 + src/common/sphere_library/stypecast.h | 472 ++++++++++++++++-------- src/game/items/CItemMultiCustom.cpp | 2 +- 4 files changed, 325 insertions(+), 163 deletions(-) create mode 100644 src/common/sphere_library/stypecast.cpp diff --git a/src/CMakeSources.cmake b/src/CMakeSources.cmake index d1b52321f..fbecf9e6b 100644 --- a/src/CMakeSources.cmake +++ b/src/CMakeSources.cmake @@ -8,7 +8,7 @@ set(pch_options PRIVATE src/common/sphere_library/sstringobjs.h PRIVATE src/common/CException.h PRIVATE src/common/CExpression.h - PRIVATE src/common/CLog.h + #PRIVATE src/common/CLog.h #PRIVATE src/common/CServerMap.h PRIVATE src/game/CObjBase.h #PRIVATE src/game/CSector.h @@ -297,6 +297,7 @@ set(spherelibrary_SRCS src/common/sphere_library/sstring.h src/common/sphere_library/sstringobjs.cpp src/common/sphere_library/sstringobjs.h + src/common/sphere_library/stypecast.cpp src/common/sphere_library/stypecast.h ) source_group(common\\sphere_library FILES ${spherelibrary_SRCS}) diff --git a/src/common/sphere_library/stypecast.cpp b/src/common/sphere_library/stypecast.cpp new file mode 100644 index 000000000..f0e0c3de4 --- /dev/null +++ b/src/common/sphere_library/stypecast.cpp @@ -0,0 +1,11 @@ +#include "../CLog.h" +#include "stypecast.h" + +namespace detail_stypecast { + +void LogEventWarnWrapper(const char* warn_str) +{ + g_Log.EventWarn(warn_str); +} + +} diff --git a/src/common/sphere_library/stypecast.h b/src/common/sphere_library/stypecast.h index ebbade7cb..d367c41f1 100644 --- a/src/common/sphere_library/stypecast.h +++ b/src/common/sphere_library/stypecast.h @@ -1,11 +1,20 @@ #ifndef _INC_STYPECAST_H #define _INC_STYPECAST_H -//#include "../CLog.h" #include #include #include +namespace detail_stypecast +{ +void LogEventWarnWrapper(const char* warn_str); +} + +// Helper macros +//#define n64_narrow_n32_assert(source_val) (n64_narrow_n32_checked(source_val, true)) +//#define n64_narrow_n32_warn(source_val) (n64_narrow_n32_checked(source_val, false)) + + // Helper template to work on enum types. // Primary template for non-enum types, T will simply be itself @@ -30,19 +39,19 @@ using underlying_or_self_t = typename underlying_or_self::type; // Use this as a double check, to be sure at compile time that the two variables have the same size and sign. template [[nodiscard]] -constexpr Tout n_alias_cast(const Tin a) noexcept +constexpr Tout n_alias_cast(const Tin source_val) noexcept { static_assert(std::is_arithmetic_v, "Input variable is not an arithmetictype."); static_assert(std::is_arithmetic_v, "Output variable is not an arithmetic type."); static_assert(sizeof(Tin) == sizeof(Tout), "Input and output types do not have the same size."); static_assert(!(std::is_signed_v && std::is_unsigned_v), "Casting signed to unsigned."); static_assert(!(std::is_signed_v && std::is_unsigned_v ), "Casting unsigned to signed."); - return static_cast(a); + return static_cast(source_val); } template [[nodiscard]] -constexpr Tout enum_alias_cast(const Tin a) noexcept +constexpr Tout enum_alias_cast(const Tin source_val) noexcept { static_assert(std::is_enum_v || std::is_enum_v, "Nor input nor output variables are an enum."); static_assert(std::is_arithmetic_v || std::is_enum_v, "Input variable is not a numeric type."); @@ -68,7 +77,7 @@ constexpr Tout enum_alias_cast(const Tin a) noexcept "Casting unsigned to signed."); */ - return static_cast(a); + return static_cast(source_val); } @@ -84,7 +93,7 @@ constexpr Tout enum_alias_cast(const Tin a) noexcept // Promote to the corresponding 32 bits numeric type a smaller numeric variable. template [[nodiscard]] -constexpr auto n_promote_n32(const T a) noexcept +constexpr auto n_promote_n32(const T source_val) noexcept { static_assert(std::is_arithmetic_v, "Input variable has not a arithmetic type."); static_assert(std::is_integral_v || (std::is_floating_point_v && std::is_signed_v), "Unsigned floating point numbers are unsupported by the language standard"); @@ -92,25 +101,25 @@ constexpr auto n_promote_n32(const T a) noexcept if constexpr (std::is_signed_v) { if constexpr (std::is_floating_point_v) - return static_cast(a); - return static_cast(a); + return static_cast(source_val); + return static_cast(source_val); } else - return static_cast(a); + return static_cast(source_val); } template [[nodiscard]] -constexpr auto enum_promote_n32(const T a) noexcept +constexpr auto enum_promote_n32(const T source_val) noexcept { static_assert(std::is_enum_v, "Input variable is not an enum type."); - return n_promote_n32(static_cast>(a)); + return n_promote_n32(static_cast>(source_val)); } // Promote to the corresponding 64 bits numeric type a smaller numeric variable. template [[nodiscard]] -constexpr auto n_promote_n64(const T a) noexcept +constexpr auto n_promote_n64(const T source_val) noexcept { static_assert(std::is_arithmetic_v, "Input variable has not a arithmetic type."); static_assert(std::is_integral_v || (std::is_floating_point_v && std::is_signed_v), "Unsigned floating point numbers are unsupported by the language standard"); @@ -118,25 +127,25 @@ constexpr auto n_promote_n64(const T a) noexcept if constexpr (std::is_signed_v) { if constexpr (std::is_floating_point_v) - return static_cast(a); - return static_cast(a); + return static_cast(source_val); + return static_cast(source_val); } else - return static_cast(a); + return static_cast(source_val); } template [[nodiscard]] -constexpr auto enum_promote_n64(const T a) noexcept +constexpr auto enum_promote_n64(const T source_val) noexcept { static_assert(std::is_enum_v, "Input variable is not an enum type."); - return n_promote_n64(static_cast>(a)); + return n_promote_n64(static_cast>(source_val)); } // Narrow a 64 bits number to a 32 bits number, discarding any upper exceeding bytes. template [[nodiscard]] -constexpr auto n64_narrow_n32(const T a) noexcept +constexpr auto n64_narrow_n32(const T source_val) noexcept { static_assert(std::is_arithmetic_v, "Input variable has not a arithmetic type."); static_assert(std::is_integral_v || (std::is_floating_point_v && std::is_signed_v), "Unsigned floating point numbers are unsupported by the language standard"); @@ -147,40 +156,55 @@ constexpr auto n64_narrow_n32(const T a) noexcept if constexpr (std::is_signed_v) { if constexpr (std::is_floating_point_v) - return static_cast(a & umask); - return static_cast(a & umask); + return static_cast(source_val & umask); + return static_cast(source_val & umask); } else - return static_cast(a & umask); + return static_cast(source_val & umask); } -// Narrow a 64 bits number to a 32 bits number and ASSERT (because you're reasonably sure but not absolutely certain) that it won't overflow. +// Narrow a 64 bits number to a 32 bits number. +// ASSERT (because you're reasonably sure but not absolutely certain) that it won't overflow, otherwise +// otherwise just print an error if it overflows (wise to do this if the values depends from user input/scripts). template [[nodiscard]] inline -auto n64_narrow_n32_checked(const T a) + auto n64_narrow_n32_checked(const T source_val, bool should_assert) { - if constexpr (std::is_signed_v) { - ASSERT(a <= std::numeric_limits::max()); + if (should_assert) + { + if constexpr (std::is_signed_v) { + ASSERT(source_val <= std::numeric_limits::max()); + } + else { + ASSERT(source_val <= std::numeric_limits::max()); + } } - else { - ASSERT(a <= std::numeric_limits::max()); + else + { + if constexpr (std::is_signed_v) { + if (source_val > std::numeric_limits::max()) + detail_stypecast::LogEventWarnWrapper("[Internal] Narrowing conversion from 64 to 32 bits signed integer will overflow.\n"); + } + else { + if (source_val > std::numeric_limits::max()) + detail_stypecast::LogEventWarnWrapper("[Internal] Narrowing conversion from 64 to 32 bits unsigned integer will overflow.\n"); + } } - return n64_narrow_n32(a); + return n64_narrow_n32(source_val); } template [[nodiscard]] -constexpr auto enum64_narrow_n32_checked(const T a) noexcept +constexpr auto enum64_narrow_n32_checked(const T source_val, bool should_assert) noexcept { static_assert(std::is_enum_v, "Input variable is not an enum type."); - return n64_narrow_n32_checked(static_cast>(a)); + return n64_narrow_n32_checked(static_cast>(source_val, should_assert)); } - // Narrow a 64 bits number to a 16 bits number, discarding any upper exceeding bytes. template [[nodiscard]] -constexpr auto n64_narrow_n16(const T a) noexcept +constexpr auto n64_narrow_n16(const T source_val) noexcept { static_assert(std::is_arithmetic_v, "Input variable has not a arithmetic type."); static_assert(std::is_integral_v || (std::is_floating_point_v && std::is_signed_v), "Unsigned floating point numbers are unsupported by the language standard"); @@ -191,39 +215,56 @@ constexpr auto n64_narrow_n16(const T a) noexcept if constexpr (std::is_signed_v) { if constexpr (std::is_floating_point_v) - return static_cast(a & umask); - return static_cast(a & umask); + return static_cast(source_val & umask); + return static_cast(source_val & umask); } else - return static_cast(a & umask); + return static_cast(source_val & umask); } -// Narrow a 64 bits number to a 16 bits number and ASSERT (because you're reasonably sure but not absolutely certain) that it won't overflow. +// Narrow a 64 bits number to a 16 bits number. +// ASSERT (because you're reasonably sure but not absolutely certain) that it won't overflow, otherwise +// otherwise just print an error if it overflows (wise to do this if the values depends from user input/scripts). template [[nodiscard]] inline -auto n64_narrow_n16_checked(const T a) + auto n64_narrow_n16_checked(const T source_val, bool should_assert) { - if constexpr (std::is_signed_v) { - ASSERT(a <= std::numeric_limits::max()); + if (should_assert) + { + if constexpr (std::is_signed_v) { + ASSERT(source_val <= std::numeric_limits::max()); + } + else { + ASSERT(source_val <= std::numeric_limits::max()); + } } - else { - ASSERT(a <= std::numeric_limits::max()); + else + { + if constexpr (std::is_signed_v) { + if (source_val > std::numeric_limits::max()) + detail_stypecast::LogEventWarnWrapper("[Internal] Narrowing conversion from 64 to 16 bits signed integer will overflow.\n"); + } + else { + if (source_val > std::numeric_limits::max()) + detail_stypecast::LogEventWarnWrapper("[Internal] Narrowing conversion from 64 to 16 bits unsigned integer will overflow.\n"); + } } - return n64_narrow_n16(a); + return n64_narrow_n16(source_val); } + template [[nodiscard]] -constexpr auto enum64_narrow_n16_checked(const T a) noexcept +constexpr auto enum64_narrow_n16_checked(const T source_val, bool should_assert) noexcept { static_assert(std::is_enum_v, "Input variable is not an enum type."); - return n64_narrow_n16_checked(static_cast>(a)); + return n64_narrow_n16_checked(static_cast>(source_val, should_assert)); } -// Narrow a 64 bits number to a 8 bits number, discarding any upper exceeding bytes. +// Narrow a 64 bits number to a 8 a number, discarding any upper exceeding bytes. template [[nodiscard]] -constexpr auto n64_narrow_n8(const T a) noexcept +constexpr auto n64_narrow_n8(const T source_val) noexcept { static_assert(std::is_arithmetic_v, "Input variable has not a arithmetic type"); static_assert(std::is_floating_point_v == false, "Corresponding 8-bit floating point type does not exist?"); @@ -233,37 +274,53 @@ constexpr auto n64_narrow_n8(const T a) noexcept // Since the narrowing can be implementation specific, here we decide that we take only the lower 8 bytes and discard the upper ones. constexpr uint64 umask = 0x0000'0000'0000'00FF; if constexpr (std::is_signed_v) - return static_cast(a & umask); + return static_cast(source_val & umask); else - return static_cast(a & umask); + return static_cast(source_val & umask); } -// Narrow a 64 bits number to a 8 bits number and ASSERT (because you're reasonably sure but not absolutely certain) that it won't overflow. +// Narrow a 64 bits number to a 8 bits number. +// ASSERT (because you're reasonably sure but not absolutely certain) that it won't overflow, otherwise +// otherwise just print an error if it overflows (wise to do this if the values depends from user input/scripts). template [[nodiscard]] inline -auto n64_narrow_n8_checked(const T a) + auto n64_narrow_n8_checked(const T source_val, bool should_assert) { - if constexpr (std::is_signed_v) { - ASSERT(a <= std::numeric_limits::max()); + if (should_assert) + { + if constexpr (std::is_signed_v) { + ASSERT(source_val <= std::numeric_limits::max()); + } + else { + ASSERT(source_val <= std::numeric_limits::max()); + } } - else { - ASSERT(a <= std::numeric_limits::max()); + else + { + if constexpr (std::is_signed_v) { + if (source_val > std::numeric_limits::max()) + detail_stypecast::LogEventWarnWrapper("[Internal] Narrowing conversion from 64 to 8 bits signed integer will overflow.\n"); + } + else { + if (source_val > std::numeric_limits::max()) + detail_stypecast::LogEventWarnWrapper("[Internal] Narrowing conversion from 64 to 8 bits unsigned integer will overflow.\n"); + } } - return n64_narrow_n8(a); + return n64_narrow_n8(source_val); } template [[nodiscard]] -constexpr auto enum64_narrow_n8_checked(const T a) noexcept +constexpr auto enum64_narrow_n8_checked(const T source_val, bool should_assert) noexcept { static_assert(std::is_enum_v, "Input variable is not an enum type."); - return n64_narrow_n8_checked(static_cast>(a)); + return n64_narrow_n8_checked(static_cast>(source_val, should_assert)); } // Narrow a 32 bits number to a 16 bits number, discarding any upper exceeding bytes. template [[nodiscard]] -constexpr auto n32_narrow_n16(const T a) noexcept +constexpr auto n32_narrow_n16(const T source_val) noexcept { static_assert(std::is_arithmetic_v, "Input variable has not a arithmetic type."); static_assert(std::is_integral_v || (std::is_floating_point_v && std::is_signed_v), "Unsigned floating point numbers are unsupported by the language standard"); @@ -274,39 +331,55 @@ constexpr auto n32_narrow_n16(const T a) noexcept if constexpr (std::is_signed_v) { if constexpr (std::is_floating_point_v) - return static_cast(a & umask); - return static_cast(a & umask); + return static_cast(source_val & umask); + return static_cast(source_val & umask); } else - return static_cast(a & umask); + return static_cast(source_val & umask); } -// Narrow a 32 bits number to a 16 bits number and ASSERT (because you're reasonably sure but not absolutely certain) that it won't overflow. +// Narrow a 32 bits number to a 16 bits number. +// ASSERT (because you're reasonably sure but not absolutely certain) that it won't overflow, otherwise +// otherwise just print an error if it overflows (wise to do this if the values depends from user input/scripts). template [[nodiscard]] inline -auto n32_narrow_n16_checked(const T a) + auto n32_narrow_n16_checked(const T source_val, bool should_assert) { - if constexpr (std::is_signed_v) { - ASSERT(a <= std::numeric_limits::max()); + if (should_assert) + { + if constexpr (std::is_signed_v) { + ASSERT(source_val <= std::numeric_limits::max()); + } + else { + ASSERT(source_val <= std::numeric_limits::max()); + } } - else { - ASSERT(a <= std::numeric_limits::max()); + else + { + if constexpr (std::is_signed_v) { + if (source_val > std::numeric_limits::max()) + detail_stypecast::LogEventWarnWrapper("[Internal] Narrowing conversion from 32 to 16 bits signed integer will overflow.\n"); + } + else { + if (source_val > std::numeric_limits::max()) + detail_stypecast::LogEventWarnWrapper("[Internal] Narrowing conversion from 32 to 16 bits unsigned integer will overflow.\n"); + } } - return n32_narrow_n16(a); + return n32_narrow_n16(source_val); } template [[nodiscard]] -constexpr auto enum32_narrow_n16_checked(const T a) noexcept +constexpr auto enum32_narrow_n16_checked(const T source_val, bool should_assert) noexcept { static_assert(std::is_enum_v, "Input variable is not an enum type."); - return n32_narrow_n16_checked(static_cast>(a)); + return n32_narrow_n16_checked(static_cast>(source_val, should_assert)); } // Narrow a 32 bits number to a 8 bits number, discarding any upper exceeding bytes. template [[nodiscard]] -constexpr auto n32_narrow_n8(const T a) noexcept +constexpr auto n32_narrow_n8(const T source_val) noexcept { static_assert(std::is_arithmetic_v, "Input variable has not a arithmetic type."); static_assert(sizeof(T) == 4, "Input variable is not a 32 bit number."); @@ -314,37 +387,53 @@ constexpr auto n32_narrow_n8(const T a) noexcept // Since the narrowing can be implementation specific, here we decide that we take only the lower 16 bytes and discard the upper ones. constexpr uint32 umask = 0x0000'00FF; if constexpr (std::is_signed_v) - return static_cast (a & umask); + return static_cast (source_val & umask); else - return static_cast(a & umask); + return static_cast(source_val & umask); } -// Narrow a 32 bits number to an 8 bits number and ASSERT (because you're reasonably sure but not absolutely certain) that it won't overflow. +// Narrow a 32 bits number to a 16 bits number. +// ASSERT (because you're reasonably sure but not absolutely certain) that it won't overflow, otherwise +// otherwise just print an error if it overflows (wise to do this if the values depends from user input/scripts). template [[nodiscard]] inline -auto n32_narrow_n8_checked(const T a) + auto n32_narrow_n8_checked(const T source_val, bool should_assert) { - if constexpr (std::is_signed_v) { - ASSERT(a <= std::numeric_limits::max()); + if (should_assert) + { + if constexpr (std::is_signed_v) { + ASSERT(source_val <= std::numeric_limits::max()); + } + else { + ASSERT(source_val <= std::numeric_limits::max()); + } } - else { - ASSERT(a <= std::numeric_limits::max()); + else + { + if constexpr (std::is_signed_v) { + if (source_val > std::numeric_limits::max()) + detail_stypecast::LogEventWarnWrapper("[Internal] Narrowing conversion from 32 to 8 bits signed integer will overflow.\n"); + } + else { + if (source_val > std::numeric_limits::max()) + detail_stypecast::LogEventWarnWrapper("[Internal] Narrowing conversion from 32 to 8 bits unsigned integer will overflow.\n"); + } } - return n32_narrow_n8(a); + return n32_narrow_n8(source_val); } template [[nodiscard]] -constexpr auto enum32_narrow_n8_checked(const T a) noexcept +constexpr auto enum32_narrow_n8_checked(const T source_val, bool should_assert) noexcept { static_assert(std::is_enum_v, "Input variable is not an enum type."); - return n32_narrow_n8_checked(static_cast>(a)); + return n32_narrow_n8_checked(static_cast>(source_val, should_assert)); } // Narrow a 16 bits number to an 8 bits number, discarding any upper exceeding bytes. template [[nodiscard]] -constexpr auto n16_narrow_n8(const T a) noexcept +constexpr auto n16_narrow_n8(const T source_val) noexcept { static_assert(std::is_arithmetic_v, "Input variable has not a arithmetic type."); static_assert(std::is_integral_v, "Only integral types are supported by this function."); @@ -353,46 +442,62 @@ constexpr auto n16_narrow_n8(const T a) noexcept // Since the narrowing can be implementation specific, here we decide that we take only the lower 16 bytes and discard the upper ones. constexpr uint16 umask = 0x00FF; if constexpr (std::is_signed_v) - return static_cast(a & umask); + return static_cast(source_val & umask); else - return static_cast(a & umask); + return static_cast(source_val & umask); } -// Narrow a 16 bits number to an 8 bits number and ASSERT (because you're reasonably sure but not absolutely certain) that it won't overflow. +// Narrow a 32 bits number to a 16 bits number. +// ASSERT (because you're reasonably sure but not absolutely certain) that it won't overflow, otherwise +// otherwise just print an error if it overflows (wise to do this if the values depends from user input/scripts). template [[nodiscard]] inline -auto n16_narrow_n8_checked(const T a) + auto n16_narrow_n8_checked(const T source_val, bool should_assert) { - if constexpr (std::is_signed_v) { - ASSERT(a <= std::numeric_limits::max()); + if (should_assert) + { + if constexpr (std::is_signed_v) { + ASSERT(source_val <= std::numeric_limits::max()); + } + else { + ASSERT(source_val <= std::numeric_limits::max()); + } } - else { - ASSERT(a <= std::numeric_limits::max()); + else + { + if constexpr (std::is_signed_v) { + if (source_val > std::numeric_limits::max()) + detail_stypecast::LogEventWarnWrapper("[Internal] Narrowing conversion from 16 to 8 bits signed integer will overflow.\n"); + } + else { + if (source_val > std::numeric_limits::max()) + detail_stypecast::LogEventWarnWrapper("[Internal] Narrowing conversion from 16 to 8 bits unsigned integer will overflow.\n"); + } } - return n16_narrow_n8(a); + return n16_narrow_n8(source_val); } template [[nodiscard]] -constexpr auto enum16_narrow_n8_checked(const T a) noexcept +constexpr auto enum16_narrow_n8_checked(const T source_val, bool should_assert) noexcept { static_assert(std::is_enum_v, "Input variable is not an enum type."); - return n16_narrow_n8_checked(static_cast>(a)); + return n16_narrow_n8_checked(static_cast>(source_val, should_assert)); } // If size_t is bigger than a 32 bits number, narrow it to a 32 bits number discarding any upper exceeding bytes, otherwise plain return the same value.. [[nodiscard]] -constexpr uint32 usize_narrow_u32(const size_t a) noexcept +constexpr uint32 usize_narrow_u32(const size_t source_val) noexcept { // This doesn't work because n64_narrow_n32 static_asserts will be evaluated and fail on 32 bits compilation. /* if constexpr (sizeof(size_t) == 8) - return n64_narrow_n32(a); + return n64_narrow_n32(source_val); else return a; */ #if SIZE_MAX == UINT64_MAX - return n64_narrow_n32(a); + return n64_narrow_n32(source_val); #elif SIZE_MAX == UINT32_MAX return a; #else @@ -402,177 +507,222 @@ constexpr uint32 usize_narrow_u32(const size_t a) noexcept // If size_t is bigger than a 32 bits number, narrow it to a 32 bits number and ASSERT (because you're reasonably sure but not absolutely certain) that it won't overflow. If size_t has 32 bits size, plain return the same value. [[nodiscard]] inline -uint32 usize_narrow_u32_checked(const size_t a) +uint32 usize_narrow_u32_checked(const size_t source_val, bool should_assert) { - ASSERT(a <= std::numeric_limits::max()); - return usize_narrow_u32(a); + if (should_assert) + ASSERT(source_val <= std::numeric_limits::max()); + else if (source_val > std::numeric_limits::max()) + detail_stypecast::LogEventWarnWrapper("[Internal] Narrowing conversion from size_t to 32 bits unsigned integer will overflow.\n"); + + return usize_narrow_u32(source_val); } /* Unsigned (and size_t) to signed, clamping. */ [[nodiscard]] constexpr - int8 i8_from_u8_clamping(const uint8 a) noexcept + int8 i8_from_u8_clamping(const uint8 source_val) noexcept { - return (a > (uint8_t)std::numeric_limits::max()) ? std::numeric_limits::max() : (int8_t)a; + return (source_val > (uint8_t)std::numeric_limits::max()) ? std::numeric_limits::max() : (int8_t)source_val; } [[nodiscard]] constexpr - int16 i16_from_u16_clamping(const uint16 a) noexcept + int16 i16_from_u16_clamping(const uint16 source_val) noexcept { - return (a > (uint16_t)std::numeric_limits::max()) ? std::numeric_limits::max() : (int16_t)a; + return (source_val > (uint16_t)std::numeric_limits::max()) ? std::numeric_limits::max() : (int16_t)source_val; } [[nodiscard]] constexpr - int32 i32_from_u32_clamping(const uint32 a) noexcept + int32 i32_from_u32_clamping(const uint32 source_val) noexcept { - return (a > (uint32_t)std::numeric_limits::max()) ? std::numeric_limits::max() : (int32_t)a; + return (source_val > (uint32_t)std::numeric_limits::max()) ? std::numeric_limits::max() : (int32_t)source_val; } [[nodiscard]] constexpr - int64 i64_from_u64_clamping(const uint64 a) noexcept + int64 i64_from_u64_clamping(const uint64 source_val) noexcept { - return (a > (uint64_t)std::numeric_limits::max()) ? std::numeric_limits::max() : (int64_t)a; + return (source_val > (uint64_t)std::numeric_limits::max()) ? std::numeric_limits::max() : (int64_t)source_val; } [[nodiscard]] constexpr - int32 i32_from_usize_clamping(const size_t a) noexcept + int32 i32_from_usize_clamping(const size_t source_val) noexcept { - return (a > (size_t)std::numeric_limits::max()) ? std::numeric_limits::max() : (int32_t)a; + return (source_val > (size_t)std::numeric_limits::max()) ? std::numeric_limits::max() : (int32_t)source_val; } [[nodiscard]] constexpr - int64 i64_from_usize_clamping(const size_t a) noexcept + int64 i64_from_usize_clamping(const size_t source_val) noexcept { - return (a > (size_t)std::numeric_limits::max()) ? std::numeric_limits::max() : (int64_t)a; + return (source_val > (size_t)std::numeric_limits::max()) ? std::numeric_limits::max() : (int64_t)source_val; } [[nodiscard]] constexpr - uint32 u32_from_usize_clamping(const size_t a) noexcept + uint32 u32_from_usize_clamping(const size_t source_val) noexcept { if constexpr (sizeof(size_t) == 8) - return (a > (size_t)std::numeric_limits::max()) ? std::numeric_limits::max() : (uint32_t)a; + return (source_val > (size_t)std::numeric_limits::max()) ? std::numeric_limits::max() : (uint32_t)source_val; else - return a; + return source_val; } /* Unsigned (and size_t) to signed, checked for overflows. */ -// Convert an 8 bits unsigned value to signed and ASSERT (because you're reasonably sure but not absolutely certain) that it will fit into its signed datatype counterpart (unsigned variables can store greater values than signed ones). [[nodiscard]] inline - int8 i8_from_u8_checked(const uint8 a) // not clamping/capping + int8 i8_from_u8_checked(const uint8 source_val, bool should_assert) // not clamping/capping +{ + const bool would_overflow = (source_val > (uint8)std::numeric_limits::max()); + if (should_assert) + ASSERT(!would_overflow); + else if (would_overflow) + detail_stypecast::LogEventWarnWrapper("[Internal] Narrowing conversion from 8 bits unsigned integer to 8 bits signed integer will overflow.\n"); + return static_cast(source_val); +} +template int8 i8_from_u8_checked(T, bool) = delete; // disable implicit type conversion for the inpuT source_valrgument + +[[nodiscard]] inline + int16 i8_from_u16_checked(const uint16 source_val, bool should_assert) // not clamping/capping { - ASSERT(a <= (uint8_t)std::numeric_limits::max()); - return static_cast(a); + const bool would_overflow = (source_val > (uint16)std::numeric_limits::max()); + if (should_assert) + ASSERT(!would_overflow); + else if (would_overflow) + detail_stypecast::LogEventWarnWrapper("[Internal] Narrowing conversion from 16 bits unsigned integer to 8 bits signed integer will overflow.\n"); + + return static_cast(source_val); } -template int8 i8_from_u8_checked(T) = delete; // disable implicit type conversion for the input argument +template int16 i8_from_u16_checked(T, bool) = delete; // disable implicit type conversion for the inpuT source_valrgument -// Convert a 16 bits unsigned value to signed and ASSERT (because you're reasonably sure but not absolutely certain) that it will fit into its signed datatype counterpart (unsigned variables can store greater values than signed ones). [[nodiscard]] inline - int16 i16_from_u16_checked(const uint16 a) // not clamping/capping + int16 i16_from_u16_checked(const uint16 source_val, bool should_assert) // not clamping/capping { - ASSERT(a <= (uint16_t)std::numeric_limits::max()); - return static_cast(a); + const bool would_overflow = (source_val > (uint16)std::numeric_limits::max()); + if (should_assert) + ASSERT(!would_overflow); + else if (would_overflow) + detail_stypecast::LogEventWarnWrapper("[Internal] Narrowing conversion from 16 bits unsigned integer to 16 bits signed integer will overflow.\n"); + + return static_cast(source_val); } -template int16 i16_from_u16_checked(T) = delete; // disable implicit type conversion for the input argument +template int16 i16_from_u16_checked(T, bool) = delete; // disable implicit type conversion for the inpuT source_valrgument [[nodiscard]] inline - int16 i16_from_u32_checked(const uint32 a) // not clamping/capping + int16 i16_from_u32_checked(const uint32 source_val, bool should_assert) // not clamping/capping { - ASSERT(a <= (uint32_t)std::numeric_limits::max()); - return static_cast(a); + const bool would_overflow = (source_val > (uint32)std::numeric_limits::max()); + if (should_assert) + ASSERT(!would_overflow); + else if (would_overflow) + detail_stypecast::LogEventWarnWrapper("[Internal] Narrowing conversion from 32 bits unsigned integer to 16 bits signed integer will overflow.\n"); + + return static_cast(source_val); } -template int16 i16_from_u32_checked(T) = delete; // disable implicit type conversion for the input argument +template int16 i16_from_u32_checked(T, bool) = delete; // disable implicit type conversion for the inpuT source_valrgument [[nodiscard]] inline - int16 i16_from_u64_checked(const uint64 a) // not clamping/capping + int16 i16_from_u64_checked(const uint64 source_val, bool should_assert) // not clamping/capping { - ASSERT(a <= (uint64_t)std::numeric_limits::max()); - return static_cast(a); + const bool would_overflow = (source_val > (uint64)std::numeric_limits::max()); + if (should_assert) + ASSERT(!would_overflow); + else if (would_overflow) + detail_stypecast::LogEventWarnWrapper("[Internal] Narrowing conversion from 64 bits unsigned integer to 16 bits signed integer will overflow.\n"); + return static_cast(source_val); } -template int16 i16_from_u64_checked(T) = delete; // disable implicit type conversion for the input argument +template int16 i16_from_u64_checked(T, bool) = delete; // disable implicit type conversion for the inpuT source_valrgument // Convert a 32 bits unsigned value to signed and ASSERT (because you're reasonably sure but not absolutely certain) that it will fit into its signed datatype counterpart (unsigned variables can store greater values than signed ones). [[nodiscard]] inline - int32 i32_from_u32_checked(const uint32 a) // not clamping/capping + int32 i32_from_u32_checked(const uint32 source_val, bool should_assert) // not clamping/capping { - ASSERT(a <= (uint32_t)std::numeric_limits::max()); - return static_cast(a); + const bool would_overflow = (source_val > (uint32)std::numeric_limits::max()); + if (should_assert) + ASSERT(!would_overflow); + else if (would_overflow) + detail_stypecast::LogEventWarnWrapper("[Internal] Narrowing conversion from 32 bits unsigned integer to 32 bits signed integer will overflow.\n"); + return static_cast(source_val); } -template int32 i32_from_u32_checked(T) = delete; // disable implicit type conversion for the input argument +template int32 i32_from_u32_checked(T, bool) = delete; // disable implicit type conversion for the inpuT source_valrgument [[nodiscard]] inline - int32 i32_from_u64_checked(const uint64 a) // not clamping/capping + int32 i32_from_u64_checked(const uint64 source_val, bool should_assert) // not clamping/capping { - ASSERT(a <= (uint64_t)std::numeric_limits::max()); - return static_cast(a); + const bool would_overflow = (source_val > (uint64)std::numeric_limits::max()); + if (should_assert) + ASSERT(!would_overflow); + else if (would_overflow) + detail_stypecast::LogEventWarnWrapper("[Internal] Narrowing conversion from 64 bits unsigned integer to 32 bits signed integer will overflow.\n"); + return static_cast(source_val); } -template int32 i32_from_u64_checked(T) = delete; // disable implicit type conversion for the input argument +template int32 i32_from_u64_checked(T, bool) = delete; // disable implicit type conversion for the inpuT source_valrgument // Convert a 64 bits unsigned value to signed and ASSERT (because you're reasonably sure but not absolutely certain) that it will fit into its signed datatype counterpart (unsigned variables can store greater values than signed ones). [[nodiscard]] inline - int64 i64_from_u64_checked(const uint64 a) // not clamping/capping + int64 i64_from_u64_checked(const uint64 source_val, bool should_assert) // not clamping/capping { - ASSERT(a <= (uint64_t)std::numeric_limits::max()); - return static_cast(a); + const bool would_overflow = (source_val > (uint64)std::numeric_limits::max()); + if (should_assert) + ASSERT(!would_overflow); + else if (would_overflow) + detail_stypecast::LogEventWarnWrapper("[Internal] Narrowing conversion from 64 bits unsigned integer to 64 bits signed integer will overflow.\n"); + return static_cast(source_val); } -template int64 i64_from_u64_checked(T) = delete; // disable implicit type conversion for the input argument +template int64 i64_from_u64_checked(T, bool) = delete; // disable implicit type conversion for the inpuT source_valrgument // size_t conversions [[nodiscard]] inline - int8 i8_from_usize_checked(const size_t a) // not clamping/capping + int8 i8_from_usize_checked(const size_t source_val, bool should_assert) // not clamping/capping { #if SIZE_MAX == UINT64_MAX - return n64_narrow_n8_checked(a); + return n64_narrow_n8_checked(source_val, should_assert); #elif SIZE_MAX == UINT32_MAX - return n32_narrow_n8_checked(a); + return n32_narrow_n8_checked(source_val); #else # error "size_t is neither 8 nor 4 bytes?" #endif } -template int8 i8_from_usize_checked(T) = delete; // disable implicit type conversion for the input argument +template int8 i8_from_usize_checked(T, bool) = delete; // disable implicit type conversion for the inpuT source_valrgument [[nodiscard]] inline - int16 i16_from_usize_checked(const size_t a) // not clamping/capping + int16 i16_from_usize_checked(const size_t source_val, bool should_assert) // not clamping/capping { #if SIZE_MAX == UINT64_MAX - return n64_narrow_n16_checked(a); + return n64_narrow_n16_checked(source_val, should_assert); #elif SIZE_MAX == UINT32_MAX - return n32_narrow_n16_checked(a); + return n32_narrow_n16_checked(source_val); #else # error "size_t is neither 8 nor 4 bytes?" #endif } -template int16 i16_from_usize_checked(T) = delete; // disable implicit type conversion for the input argument +template int16 i16_from_usize_checked(T, bool) = delete; // disable implicit type conversion for the inpuT source_valrgument [[nodiscard]] inline - int32 i32_from_usize_checked(const size_t a) // not clamping/capping + int32 i32_from_usize_checked(const size_t source_val, bool should_assert) // not clamping/capping { #if SIZE_MAX == UINT64_MAX - return i32_from_u32_clamping(n64_narrow_n32_checked(a)); + return i32_from_u32_clamping(n64_narrow_n32_checked(source_val, should_assert)); #elif SIZE_MAX == UINT32_MAX - return i32_from_u32_checked(n_alias_cast(a)); + return i32_from_u32_checked(n_alias_cast(source_val)); #else # error "size_t is neither 8 nor 4 bytes?" #endif } -template int32 i32_from_usize_checked(T) = delete; // disable implicit type conversion for the input argument +template int32 i32_from_usize_checked(T, bool) = delete; // disable implicit type conversion for the inpuT source_valrgument [[nodiscard]] inline - int64 i64_from_usize_checked(const size_t a) // not clamping/capping + int64 i64_from_usize_checked(const size_t source_val, bool should_assert) // not clamping/capping { #if SIZE_MAX == UINT64_MAX - return i64_from_u64_checked(n_alias_cast(a)); + return i64_from_u64_checked(n_alias_cast(source_val), should_assert); #elif SIZE_MAX == UINT32_MAX - return static_cast(a); // For sure it will fit + return static_cast(source_val); // For sure it will fit #else # error "size_t is neither 8 nor 4 bytes?" #endif } -template int64 i64_from_usize_checked(T) = delete; // disable implicit type conversion for the input argument +template int64 i64_from_usize_checked(T, bool) = delete; // disable implicit type conversion for the inpuT source_valrgument diff --git a/src/game/items/CItemMultiCustom.cpp b/src/game/items/CItemMultiCustom.cpp index 22e84d1d2..3cf453ec2 100644 --- a/src/game/items/CItemMultiCustom.cpp +++ b/src/game/items/CItemMultiCustom.cpp @@ -1894,7 +1894,7 @@ uint8 CItemMultiCustom::GetPlane(const CMultiComponent * pComponent) int8 CItemMultiCustom::GetPlaneZ(uint8 plane) { - return n32_narrow_n8_checked(7 + ((plane - 1) * 20)); + return n32_narrow_n8_checked(7 + ((plane - 1) * 20), true); } bool CItemMultiCustom::IsValidItem(ITEMID_TYPE id, CClient * pClientSrc, bool fMulti) From c3f890d9386478ec24a5f257e973a5cfa552f06a Mon Sep 17 00:00:00 2001 From: cbnolok Date: Thu, 3 Oct 2024 13:28:55 +0200 Subject: [PATCH 14/32] Fixed: on Windows, the console window closed itself after a failed server start attempt. --- src/sphere/ntwindow.cpp | 14 ++++++----- src/sphere/threads.cpp | 52 ++++++++++++++++++++++++++++++----------- src/sphere/threads.h | 26 +++++++++++++-------- 3 files changed, 62 insertions(+), 30 deletions(-) diff --git a/src/sphere/ntwindow.cpp b/src/sphere/ntwindow.cpp index 5b21fbb47..c9f8a049d 100644 --- a/src/sphere/ntwindow.cpp +++ b/src/sphere/ntwindow.cpp @@ -24,7 +24,7 @@ #define IDT_ONTICK 1 -CNTApp theApp; +static CNTApp theApp; //************************************ // -CAboutDlg @@ -166,6 +166,8 @@ BOOL CNTWindow::CStatusDlg::DefDialogProc( UINT message, WPARAM wParam, LPARAM l CNTWindow::CNTWindow() : AbstractSphereThread("T_ConsoleWindow", IThread::Highest), _NTWInitParams{}, m_zCommands {{}} { + _fKeepAliveAtShutdown = true; + m_iLogTextLen = 0; m_fLogScrollLock = false; m_dwColorNew = RGB( 0xaf,0xaf,0xaf ); @@ -274,14 +276,14 @@ void CNTWindow::List_AddSingle(COLORREF color, LPCTSTR ptcText) if ( iNewLen > iMaxTextLen ) { - const int iCut = iNewLen - iMaxTextLen; + const int iCut = iNewLen - iMaxTextLen; m_wndLog.SetSel( 0, iCut ); // These SetRedraw FALSE/TRUE calls will make the log panel scroll much faster when spamming text, but // it will generate some drawing artifact //m_wndLog.SetRedraw(FALSE); - m_wndLog.ReplaceSel( "" ); + m_wndLog.ReplaceSel( "" ); } else if (NTWindow_CanScroll()) theApp.m_wndMain.m_wndLog.ScrollLine(); @@ -318,7 +320,7 @@ void CNTWindow::List_AddGroup(std::deque>&& msgs) { iTotalTextLen += co->GetTextString().GetLength(); } - + const int iNewLen = m_iLogTextLen + iTotalTextLen; if (iNewLen > iMaxTextLen) @@ -1025,7 +1027,7 @@ bool CNTWindow::NTWindow_OnTick( int iWaitmSec ) iWaitmSec = 0; } } - + // Give the windows message loops a tick. for (;;) @@ -1157,7 +1159,7 @@ bool CNTWindow::NTWindow_OnTick( int iWaitmSec ) } else if ( !*pszCurSel ) // or there is still no selection { - curmatch = firstmatch; + curmatch = firstmatch; } else // need to find for the next record { diff --git a/src/sphere/threads.cpp b/src/sphere/threads.cpp index d68907d97..77dba0d3b 100644 --- a/src/sphere/threads.cpp +++ b/src/sphere/threads.cpp @@ -62,6 +62,7 @@ IThread::IThread() noexcept : IThread::~IThread() noexcept = default; #ifdef _WIN32 +/* #pragma pack(push, 8) typedef struct tagTHREADNAME_INFO { @@ -71,9 +72,12 @@ typedef struct tagTHREADNAME_INFO DWORD dwFlags; } THREADNAME_INFO; #pragma pack(pop) +*/ +#ifdef MSVC_COMPILER static constexpr DWORD MS_VC_EXCEPTION = 0x406D1388; #endif +#endif void IThread::setThreadName(const char* name) { @@ -85,7 +89,7 @@ void IThread::setThreadName(const char* name) Str_CopyLimitNull(name_trimmed, name, m_nameMaxLength); #if defined(_WIN32) - #if defined(_MSC_VER) // TODO: support thread naming when compiling with compilers other than Microsoft's + #if defined(MSVC_COMPILER) // TODO: support thread naming when compiling with compilers other than Microsoft's // Windows uses THREADNAME_INFO structure to set thread name THREADNAME_INFO info; info.dwType = 0x1000; @@ -155,18 +159,17 @@ IThread* ThreadHolder::current() noexcept RETRY_SHARED_LOCK_FOR_TASK(m_mutex, lock, retval, ([this, &lock]() -> IThread* { - if (m_closingThreads) - [[unlikely]] - { - //STDERR_LOG("Closing?\n"); - return nullptr; - } - const threadid_t tid = IThread::getCurrentThreadSystemId(); if (m_spherethreadpairs_systemid_ptr.empty()) [[unlikely]] { + if (m_closingThreads) [[unlikely]] + { + //STDERR_LOG("Closing?\n"); + return nullptr; + } + auto thread = static_cast(DummySphereThread::getInstance()); if (!thread) [[unlikely]] @@ -190,6 +193,7 @@ IThread* ThreadHolder::current() noexcept break; } } + if (!found) [[unlikely]] { @@ -211,6 +215,22 @@ IThread* ThreadHolder::current() noexcept return nullptr; } + if (m_closingThreads) [[unlikely]] + { + auto spherethread = dynamic_cast(thread); + if (!spherethread) + { + // Should never happen. + RaiseImmediateAbort(); + } + + if (!spherethread->_fKeepAliveAtShutdown) + { + //STDERR_LOG("Closing?\n"); + return nullptr; + } + } + // Uncomment it only for testing purposes, since this method is called very often and we don't need the additional overhead //DEBUG_ASSERT( thread->isSameThread(thread->getId()) ); @@ -349,6 +369,9 @@ void ThreadHolder::markThreadsClosing() CANTHROW for (auto& thread_data : m_threads) { auto sphere_thread = static_cast(thread_data.m_ptr); + if (sphere_thread->_fKeepAliveAtShutdown) + continue; + sphere_thread->_fIsClosing = true; thread_data.m_closed = true; } @@ -399,7 +422,8 @@ IThread * ThreadHolder::getThreadAt(size_t at) noexcept */ int AbstractThread::m_threadsAvailable = 0; -AbstractThread::AbstractThread(const char *name, IThread::Priority priority) +AbstractThread::AbstractThread(const char *name, IThread::Priority priority) : + _fKeepAliveAtShutdown(false), _fIsClosing(false) { if( AbstractThread::m_threadsAvailable == 0 ) { @@ -414,7 +438,7 @@ AbstractThread::AbstractThread(const char *name, IThread::Priority priority) } m_threadSystemId = 0; Str_CopyLimitNull(m_name, name, sizeof(m_name)); - m_handle = 0; + m_handle = SPHERE_THREADT_NULL; m_hangCheck = 0; _thread_selfTerminateAfterThisTick = true; m_terminateRequested = true; @@ -493,7 +517,7 @@ void AbstractThread::terminate(bool ended) // Common things ThreadHolder::get().remove(this); m_threadSystemId = 0; - m_handle = 0; + m_handle = SPHERE_THREADT_NULL; // let everyone know we have been terminated m_terminateEvent.set(); @@ -626,7 +650,7 @@ SPHERE_THREADENTRY_RETNTYPE AbstractThread::runner(void *callerThread) bool AbstractThread::isActive() const { - return (m_handle != 0); + return (m_handle != SPHERE_THREADT_NULL); } void AbstractThread::waitForClose() @@ -756,14 +780,14 @@ void AbstractThread::setPriority(IThread::Priority pri) bool AbstractThread::shouldExit() noexcept { - return m_terminateRequested || _thread_selfTerminateAfterThisTick; + return closing() || m_terminateRequested || _thread_selfTerminateAfterThisTick; } /* * AbstractSphereThread */ AbstractSphereThread::AbstractSphereThread(const char *name, Priority priority) - : AbstractThread(name, priority), _fIsClosing(false) + : AbstractThread(name, priority) { #ifdef THREAD_TRACK_CALLSTACK m_stackPos = -1; diff --git a/src/sphere/threads.h b/src/sphere/threads.h index f4ea58293..3534efbd6 100644 --- a/src/sphere/threads.h +++ b/src/sphere/threads.h @@ -31,6 +31,7 @@ typedef DWORD threadid_t; #define SPHERE_THREADENTRY_RETNTYPE unsigned #define SPHERE_THREADENTRY_CALLTYPE __stdcall + #define SPHERE_THREADT_NULL nullptr #else typedef pthread_t spherethread_t; #ifdef __APPLE__ @@ -41,6 +42,7 @@ #define SPHERE_THREADENTRY_RETNTYPE void * #define SPHERE_THREADENTRY_CALLTYPE + #define SPHERE_THREADT_NULL 0 #endif class IThread; @@ -207,18 +209,21 @@ class AbstractThread : public IThread friend class ThreadHolder; protected: - bool _thread_selfTerminateAfterThisTick; + bool _fKeepAliveAtShutdown; + volatile std::atomic_bool _thread_selfTerminateAfterThisTick; + volatile std::atomic_bool _fIsClosing; private: - char m_name[30]; + volatile std::atomic_bool m_terminateRequested; + + char m_name[30]; static int m_threadsAvailable; - spherethread_t m_handle; + + spherethread_t m_handle; uint m_hangCheck; Priority m_priority; uint m_tickPeriod; AutoResetEvent m_sleepEvent; - - volatile std::atomic_bool m_terminateRequested; ManualResetEvent m_terminateEvent; public: @@ -246,13 +251,18 @@ class AbstractThread : public IThread void overwriteInternalThreadName(const char* name) noexcept; bool isCurrentThread() const noexcept; + bool closing() noexcept + { + return _fIsClosing; + } + protected: virtual void tick() = 0; // NOTE: this should not be too long-lasted function, so no world loading, etc here!!! virtual void onStart(); virtual bool shouldExit() noexcept override; -private: + private: void run(); static SPHERE_THREADENTRY_RETNTYPE SPHERE_THREADENTRY_CALLTYPE runner(void *callerThread); }; @@ -263,7 +273,6 @@ class AbstractSphereThread : public AbstractThread { friend class ThreadHolder; - bool _fIsClosing; #ifdef THREAD_TRACK_CALLSTACK struct STACK_INFO_REC { @@ -291,9 +300,6 @@ class AbstractSphereThread : public AbstractThread void getStringBuffer(TemporaryString &string) noexcept; void exceptionCaught(); - bool closing() noexcept { - return _fIsClosing; - } #ifdef THREAD_TRACK_CALLSTACK inline void freezeCallStack(bool freeze) noexcept From 28586ef1d206b74c3c1f3062b67fe66202a3cd7e Mon Sep 17 00:00:00 2001 From: cbnolok Date: Thu, 3 Oct 2024 13:31:36 +0200 Subject: [PATCH 15/32] Fixed MinGW compilation with both Clang and MSVC runtime libs. Added different macros, instead of using _MSC_VER. This one is added even when Clang with MSVC runtime, so it's not viable to check if we're compiling with MSVC. --- lib/bcrypt/bcrypt/wrapper.c | 11 +++++-- lib/libev/wrapper_ev.c | 15 +++++++--- src/common/CException.cpp | 10 ++++--- src/common/CScript.cpp | 7 ++++- src/common/CScript.h | 15 ++++++---- src/common/ListDefContMap.h | 6 ++-- src/common/common.h | 22 ++++++++++++-- src/common/crashdump/crashdump.cpp | 14 ++++----- src/common/datatypes.h | 3 +- src/common/os_windows.h | 20 +++++++------ src/common/sphere_library/CSTime.cpp | 18 +++++------ src/common/sphere_library/sptr.h | 11 +++++-- src/common/sphere_library/sstring.cpp | 14 ++++----- src/game/CServerConfig.cpp | 8 +++-- src/game/CServerDef.cpp | 12 ++++---- src/game/CWorldSearch.h | 4 +-- src/game/CWorldTicker.h | 4 +-- src/game/spheresvr.cpp | 2 +- src/game/uo_files/CUOHuesRec.h | 4 +-- src/game/uo_files/CUOIndexRec.h | 4 +-- src/game/uo_files/CUOItemTypeRec.h | 4 +-- src/game/uo_files/CUOMapBlock.h | 4 +-- src/game/uo_files/CUOMapMeter.h | 4 +-- src/game/uo_files/CUOMultiItemRec.h | 4 +-- src/game/uo_files/CUOStaticItemRec.h | 4 +-- src/game/uo_files/CUOTerrainTypeRec.h | 4 +-- src/game/uo_files/CUOVersionBlock.h | 4 +-- src/network/CNetworkOutput.cpp | 2 +- src/network/net_datatypes.h | 4 +-- src/network/packet.cpp | 6 ++-- src/resources/SphereSvr.rc | 8 ++--- src/resources/resource.h | 43 --------------------------- src/sphere/ntservice.cpp | 2 +- src/sphere/ntservice.h | 6 ++-- src/sphere/ntwindow.h | 8 ++--- 35 files changed, 160 insertions(+), 151 deletions(-) delete mode 100644 src/resources/resource.h diff --git a/lib/bcrypt/bcrypt/wrapper.c b/lib/bcrypt/bcrypt/wrapper.c index 197475b8c..6a3503f5b 100644 --- a/lib/bcrypt/bcrypt/wrapper.c +++ b/lib/bcrypt/bcrypt/wrapper.c @@ -49,8 +49,15 @@ extern struct crypt_data _ufc_foobar; char* mystrdup(const char* s) { - char* p = malloc(strlen(s)+1); - if (p) strcpy(p, s); + const size_t len = strlen(s); + char* p = malloc(len) + 1; + if (p) + { + //strcpy(p, s); + strncpy(p, s, len); + p[len] = '\0'; + } + return p; } diff --git a/lib/libev/wrapper_ev.c b/lib/libev/wrapper_ev.c index c9a7cfae2..391df69e3 100644 --- a/lib/libev/wrapper_ev.c +++ b/lib/libev/wrapper_ev.c @@ -2,15 +2,22 @@ #define _LIBEV +// Clang with MSVC backend on Windows defines _MSC_VER! (But also __clang__) +#ifndef MSVC_COMPILER +# if defined(_MSC_VER) && !defined(__clang__) +# define MSVC_COMPILER 1 +# endif +#endif + // libev produces many warnings which isn't really appropriate for us to // address since it is 3rd party code that could be overwritten at any time // with a new version -#ifdef _MSC_VER +#ifdef MSVC_COMPILER #pragma warning(push) #pragma warning(disable:4013 4068 4100 4101 4127 4133 4189 4244 4245 4456 4457 4706 4996) #else - //#define _POSIX_C_SOURCE - #define _POSIX_SOURCE 1 + //#define _POSIX_C_SOURCE 1 + //#define _POSIX_SOURCE #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wcomment" @@ -44,7 +51,7 @@ //config.h for ev.c is generated by cmake #include "libev/ev.c" -#ifdef _MSC_VER +#ifdef MSVC_COMPILER #pragma warning(pop) #else #pragma GCC diagnostic pop diff --git a/src/common/CException.cpp b/src/common/CException.cpp index 8c92641b1..683ae0239 100644 --- a/src/common/CException.cpp +++ b/src/common/CException.cpp @@ -45,7 +45,7 @@ void NotifyDebugger() { #ifdef _WIN32 - #ifdef _MSC_VER + #ifdef MSVC_COMPILER __debugbreak(); #else SetAbortImmediate(false); @@ -70,10 +70,12 @@ void SetAbortImmediate(bool on) noexcept { *_GetAbortImmediate() = on; } +#ifndef _WIN32 static bool IsAbortImmediate() noexcept { return *_GetAbortImmediate(); } +#endif void RaiseRecoverableAbort() { @@ -234,7 +236,7 @@ static void _cdecl Sphere_Purecall_Handler() void SetPurecallHandler() { // We don't want sphere to immediately exit if something calls a pure virtual method. -#ifdef _MSC_VER +#ifdef MSVC_RUNTIME _set_purecall_handler(Sphere_Purecall_Handler); #else // GCC handler for pure calls is __cxxabiv1::__cxa_pure_virtual. @@ -247,7 +249,7 @@ void SetPurecallHandler() #include "crashdump/crashdump.h" -void _cdecl Sphere_Exception_Windows( unsigned int id, struct _EXCEPTION_POINTERS* pData ) +static void _cdecl Sphere_Exception_Windows( unsigned int id, struct _EXCEPTION_POINTERS* pData ) { #ifndef _NO_CRASHDUMP if ( CrashDump::IsEnabled() ) @@ -267,7 +269,7 @@ void _cdecl Sphere_Exception_Windows( unsigned int id, struct _EXCEPTION_POINTER void SetExceptionTranslator() { -#if defined(_MSC_VER) && !defined(_DEBUG) +#ifdef MSVC_COMPILER _set_se_translator( Sphere_Exception_Windows ); #endif } diff --git a/src/common/CScript.cpp b/src/common/CScript.cpp index 681b00ff9..645ad19a0 100644 --- a/src/common/CScript.cpp +++ b/src/common/CScript.cpp @@ -9,11 +9,16 @@ #include "common.h" +/* + * TODO: + * make CScriptKey m_pszKey and m_pszVal private. + * make setter and getters methods that will automatically update the buffer lengths, held in a separate value. +*/ + /////////////////////////////////////////////////////////////// // -CScriptKey - bool CScriptKey::IsKey( lpctstr pszName ) const { ASSERT(m_pszKey); diff --git a/src/common/CScript.h b/src/common/CScript.h index 855f87fe5..605f6156d 100644 --- a/src/common/CScript.h +++ b/src/common/CScript.h @@ -31,11 +31,13 @@ class CScriptKey // Args passed with the key. bool HasArgs() const; - tchar * GetArgRaw() const; // Not need to parse at all. - tchar * GetArgStr( bool * fQuoted ); // this could be a quoted string ? - inline tchar * GetArgStr() { - return GetArgStr(nullptr); - } + + // Not need to parse at all. + tchar * GetArgRaw() const; + + // this could be a quoted string ? + tchar * GetArgStr(bool * fQuoted = nullptr); + char GetArgCVal(); uchar GetArgUCVal(); @@ -62,7 +64,8 @@ class CScriptKey dword GetArgFlag( dword dwStart, dword dwMask ); int64 GetArgLLFlag( uint64 iStart, uint64 iMask ); -public: +// This class is meant only to be inherited. +protected: CScriptKey(); CScriptKey( tchar * ptcKey, tchar * ptcArg ); ~CScriptKey() = default; diff --git a/src/common/ListDefContMap.h b/src/common/ListDefContMap.h index db86bc11e..9df957509 100644 --- a/src/common/ListDefContMap.h +++ b/src/common/ListDefContMap.h @@ -214,9 +214,9 @@ class CListDefMap void ClearKeys(lpctstr mask = nullptr); void DeleteKey( lpctstr key ); - bool r_LoadVal( lpctstr ptcKey, CScript & s ); - bool r_Write( CTextConsole *pSrc, lpctstr pszString, CSString& strVal ); - void r_WriteSave( CScript& s ); + bool r_LoadVal( lpctstr ptcKey, CScript & s ) NONVIRTUAL; + bool r_Write( CTextConsole *pSrc, lpctstr pszString, CSString& strVal ) NONVIRTUAL; + void r_WriteSave( CScript& s ) NONVIRTUAL; }; #endif // _INC_LISTDEFCONTMAP_H diff --git a/src/common/common.h b/src/common/common.h index 5e75cc24a..fdf5a2f9e 100644 --- a/src/common/common.h +++ b/src/common/common.h @@ -49,6 +49,21 @@ /* Coding helpers */ +// On Windows, Clang with MSVC runtime defines _MSC_VER! (But also __clang__). +#if !defined(_MSC_VER) || defined(__clang__) +# define NON_MSVC_COMPILER 1 +#endif + +#if defined(_MSC_VER) && !defined(__clang__) +# define MSVC_COMPILER 1 +#endif + +// On Windows, Clang can use MinGW or MSVC backend. +#ifdef _MSC_VER +# define MSVC_RUNTIME +#endif + + // Strings #define STRINGIFY_IMPL_(x) #x #define STRINGIFY(x) STRINGIFY_IMPL_(x) @@ -197,10 +212,11 @@ constexpr void UnreferencedParameter(T const&) noexcept { // b = 1-based index of arguments // (note: add 1 to index for non-static class methods because 'this' argument // is inserted in position 1) -#ifdef _MSC_VER +#ifdef MSVC_COMPILER #define __printfargs(a,b) #else - #ifdef _WIN32 + #ifdef __MINGW32__ + // Clang doesn't have a way to switch from gnu or ms style printf arguments. It just depends on the runtime used. #define __printfargs(a,b) __attribute__ ((format(gnu_printf, a, b))) #else #define __printfargs(a,b) __attribute__ ((format(printf, a, b))) @@ -210,7 +226,7 @@ constexpr void UnreferencedParameter(T const&) noexcept { /* Sanitizers utilities */ -#if defined(_MSC_VER) +#if defined(MSVC_COMPILER) #if defined(__SANITIZE_ADDRESS__) || defined(ADDRESS_SANITIZER) #define NO_SANITIZE_ADDRESS __declspec(no_sanitize_address) diff --git a/src/common/crashdump/crashdump.cpp b/src/common/crashdump/crashdump.cpp index 469a3c8dd..5f78264f2 100644 --- a/src/common/crashdump/crashdump.cpp +++ b/src/common/crashdump/crashdump.cpp @@ -45,32 +45,32 @@ void CrashDump::Disable() } } -void CrashDump::StartCrashDump( DWORD processID, DWORD threadID, struct _EXCEPTION_POINTERS* pExceptionData ) +void CrashDump::StartCrashDump( DWORD processID, DWORD threadID, struct _EXCEPTION_POINTERS* pExceptionData ) { HANDLE process = nullptr, dumpFile = nullptr; - + if (!processID || !threadID || !pExceptionData) return; process = GetCurrentProcess(); if (process == nullptr) return; - + char buf[128]; SYSTEMTIME st; GetSystemTime(&st); snprintf(buf, sizeof(buf), "sphereCrash_%02i%02i-%02i%02i%02i%04i.dmp", st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond, st.wMilliseconds); - dumpFile = CreateFile(buf, GENERIC_WRITE, FILE_SHARE_WRITE, 0, CREATE_ALWAYS, 0, 0); + dumpFile = CreateFile(buf, GENERIC_WRITE, FILE_SHARE_WRITE, nullptr, CREATE_ALWAYS, 0, nullptr); if (dumpFile == INVALID_HANDLE_VALUE) return; - + MINIDUMP_EXCEPTION_INFORMATION eInfo; eInfo.ThreadId = threadID; eInfo.ExceptionPointers = pExceptionData; eInfo.ClientPointers = true; - + m_tDumpFunction(process, processID, dumpFile, MiniDumpWithDataSegs, &eInfo, nullptr, nullptr); - + CloseHandle(dumpFile); return; } diff --git a/src/common/datatypes.h b/src/common/datatypes.h index c7125776e..16531cc31 100644 --- a/src/common/datatypes.h +++ b/src/common/datatypes.h @@ -104,7 +104,7 @@ typedef uint64_t uint64; #else // _WIN32 - #ifdef _MSC_VER // already defined on MinGW + #ifdef _MSC_VER // already defined on MinGW #include typedef SSIZE_T ssize_t; #endif // _MSC_VER @@ -115,6 +115,7 @@ typedef uint64_t uint64; #define PRIxSIZE_T "zx" #define PRIdSSIZE_T "zd" #else + // If using MSVC runtime and not GNU/MinGW. #define PRIuSIZE_T "Iu" #define PRIxSIZE_T "Ix" #define PRIdSSIZE_T "Id" diff --git a/src/common/os_windows.h b/src/common/os_windows.h index 9d8b08f31..5a0d456e1 100644 --- a/src/common/os_windows.h +++ b/src/common/os_windows.h @@ -48,16 +48,18 @@ #define NOTEXTMETRIC #define NOWH -# ifdef _MSC_VER +#if defined(_MSC_VER) && !defined(__clang__) // Workaround to a possible VS compiler bug: instead of complaining if a macro expands to a "defined" macro, // it complains if a define macro contains the words "defined" in its name... -# pragma warning(push) -# pragma warning(disable: 5105) -# endif -# include -# ifdef _MSC_VER -# pragma warning(pop) -# endif +# pragma warning(push) +# pragma warning(disable: 5105) +#endif + +#include + +#if defined(_MSC_VER) && !defined(__clang__) +# pragma warning(pop) +#endif /* file handling definitions */ @@ -76,7 +78,7 @@ #define STRICT // strict conversion of handles and pointers. #endif -#ifndef _MSC_VER // No Microsoft compiler +#ifdef __MINGW32__ // No Microsoft compiler #define _cdecl __cdecl // Not defined for mingw. diff --git a/src/common/sphere_library/CSTime.cpp b/src/common/sphere_library/CSTime.cpp index bc1ee97d4..45d3ac118 100644 --- a/src/common/sphere_library/CSTime.cpp +++ b/src/common/sphere_library/CSTime.cpp @@ -26,7 +26,7 @@ // We don't have GetSupportedTickCount on Windows versions previous to Vista/Windows Server 2008. We need to check for overflows // (which occurs every 49.7 days of continuous running of the server, if measured with GetTickCount, every 7 years // with GetSupportedTickCount) manually every time we compare two values. -# if _MSC_VER +# if MSVC_COMPILER # pragma warning(push) # pragma warning(disable: 28159) # endif @@ -35,7 +35,7 @@ # else static inline llong GetSupportedTickCount() noexcept { return (llong)GetTickCount64(); } # endif -# if _MSC_VER +# if MSVC_COMPILER # pragma warning(pop) # endif #endif @@ -173,7 +173,7 @@ static std::tm safe_localtime(const time_t t) noexcept #if defined(__unix__) || defined(__APPLE__) || defined(_POSIX_VERSION) localtime_r(&t, &atm); -#elif defined(_MSC_VER) +#elif defined(MSVC_RUNTIME) || defined(__MINGW32__) localtime_s(&atm, &t); #elif defined(__STDC_LIB_EXT1__) localtime_s(&t, &atm); @@ -221,7 +221,7 @@ static std::tm safe_gmtime(const time_t t) noexcept #if defined(__unix__) || defined(__APPLE__) || defined(_POSIX_VERSION) gmtime_r(&t, &atm); -#elif defined(_MSC_VER) +#elif defined(MSVC_RUNTIME) || defined(__MINGW32__) gmtime_s(&atm, &t); #elif defined(__STDC_LIB_EXT1__) gmtime_s(&t, &atm); @@ -256,7 +256,7 @@ std::tm CSTime::GetLocalTmPlain() const noexcept #define maxTimeBufferSize 128 #endif -#if defined(_WIN32) && defined (_MSC_VER) +#if defined(_WIN32) && defined (MSVC_COMPILER) static void __cdecl invalidParameterHandler(const wchar_t* expression, const wchar_t* function, const wchar_t* file, uint line, uintptr_t pReserved) { // bad format has been specified @@ -276,12 +276,12 @@ static void FormatDateTime(tchar * pszTemp, lpctstr pszFormat, const struct tm * ASSERT(ptmTemp != nullptr); #ifdef _WIN32 -#ifdef _MSC_VER +#ifdef MSVC_COMPILER // on windows we need to set the invalid parameter handler, or else the program will terminate when a bad format is encountered _invalid_parameter_handler newHandler, oldHandler; newHandler = static_cast<_invalid_parameter_handler>(invalidParameterHandler); oldHandler = _set_invalid_parameter_handler(newHandler); -#endif // _MSC_VER +#endif // MSVC_COMPILER try { #endif // _WIN32 @@ -298,10 +298,10 @@ static void FormatDateTime(tchar * pszTemp, lpctstr pszFormat, const struct tm * pszTemp[0] = '\0'; } -#ifdef _MSC_VER +#ifdef MSVC_COMPILER // restore previous parameter handler _set_invalid_parameter_handler(oldHandler); -#endif // _MSC_VER +#endif // MSVC_COMPILER #endif // _WIN32 } diff --git a/src/common/sphere_library/sptr.h b/src/common/sphere_library/sptr.h index 66bc169bc..ee34faaa6 100644 --- a/src/common/sphere_library/sptr.h +++ b/src/common/sphere_library/sptr.h @@ -1,14 +1,21 @@ #ifndef _INC_SPTR_H #define _INC_SPTR_H -#ifndef _MSC_VER +// On Windows, Clang with MSVC runtime defines _MSC_VER! (But also __clang__). +#ifndef NON_MSVC_COMPILER +# if !defined(_MSC_VER) || !defined(__clang__) +# define NON_MSVC_COMPILER 1 +# endif +#endif + +#if NON_MSVC_COMPILER # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant" #endif #include -#ifndef _MSC_VER +#if NON_MSVC_COMPILER # pragma GCC diagnostic pop #endif diff --git a/src/common/sphere_library/sstring.cpp b/src/common/sphere_library/sstring.cpp index 6311a1930..1c9953f30 100644 --- a/src/common/sphere_library/sstring.cpp +++ b/src/common/sphere_library/sstring.cpp @@ -4,7 +4,7 @@ #include "../CExpression.h" -#if defined(_MSC_VER) +#ifdef MSVC_COMPILER #include #pragma warning( push ) #pragma warning ( disable : ALL_CODE_ANALYSIS_WARNINGS ) @@ -22,7 +22,7 @@ #include -#ifdef _MSC_VER +#ifdef MSVC_COMPILER #pragma warning( pop ) #else #pragma GCC diagnostic pop @@ -482,7 +482,7 @@ size_t strlen_mb(const char* ptr) size_t Str_LengthUTF8(const char* strInUTF8MB) noexcept { size_t len; // number of characters in the string -#ifdef _MSC_VER +#ifdef MSVC_RUNTIME mbstowcs_s(&len, nullptr, 0, strInUTF8MB, 0); // includes null terminator len -= 1; #else @@ -1261,7 +1261,7 @@ MATCH_TYPE Str_Match(lpctstr pPattern, lpctstr pText) noexcept return MATCH_VALID; } -#ifdef _MSC_VER +#ifdef MSVC_COMPILER // /GL + /LTCG flags inline in linking phase this function, but probably in a wrong way, so that // something gets corrupted on the memory and an exception is generated later #pragma auto_inline(off) @@ -1409,7 +1409,7 @@ bool Str_Parse(tchar * pLine, tchar ** ppArg, lpctstr pszSep) noexcept return true; } -#ifdef _MSC_VER +#ifdef MSVC_COMPILER #pragma auto_inline(on) #endif @@ -1761,7 +1761,7 @@ size_t UTF8MBSTR::ConvertStringToUTF8(lpctstr strIn, char*& strOutUTF8MB) noexce strOutUTF8MB = new char[len + 1](); #if defined(_WIN32) && defined(UNICODE) -#ifdef _MSC_VER +#ifdef MSVC_RUNTIME size_t aux = 0; wcstombs_s(&aux, strOutUTF8MB, len + 1, strIn, len); #else @@ -1783,7 +1783,7 @@ size_t UTF8MBSTR::ConvertUTF8ToString(const char* strInUTF8MB, lptstr& strOut) n #if defined(_WIN32) && defined(UNICODE) // tchar is wchar_t -#ifdef _MSC_VER +#ifdef MSVC_RUNTIME size_t aux = 0; mbstowcs_s(&aux, strInUTF8MB, len + 1, strInUTF8MB, len); #else diff --git a/src/game/CServerConfig.cpp b/src/game/CServerConfig.cpp index b5a56b9e5..b30cdb9f1 100644 --- a/src/game/CServerConfig.cpp +++ b/src/game/CServerConfig.cpp @@ -741,7 +741,7 @@ enum RC_TYPE // TODO: use offsetof by cstddef. Though, it requires the class/struct to be a POD type, so we need to encapsulate the values in a separate struct. // This hack does happen because this class hasn't virtual methods? Or simply because the compiler is so smart and protects us from ourselves? -#ifdef __GNUC__ +#if NON_MSVC_COMPILER #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant" #endif @@ -1030,7 +1030,7 @@ const CAssocReg CServerConfig::sm_szLoadKeys[RC_QTY + 1] { nullptr, { ELEM_VOID, 0, }} }; -#ifdef __GNUC__ +#if defined(__GNUC__) || defined(__clang__) #pragma GCC diagnostic pop #endif @@ -3052,7 +3052,9 @@ bool CServerConfig::LoadResourceSection( CScript * pScript ) } rid = CResourceID( (dword)pVarNum->GetValNum(), 0 ); - restype = rid.GetResType(); + + // This value won't be read, since we return anyways once in this branch. + //restype = rid.GetResType(); CResourceDef * pRes = nullptr; size_t index = m_ResHash.FindKey( rid ); diff --git a/src/game/CServerDef.cpp b/src/game/CServerDef.cpp index a60500067..063600ca4 100644 --- a/src/game/CServerDef.cpp +++ b/src/game/CServerDef.cpp @@ -32,9 +32,9 @@ // PSAPI external definitions typedef intptr_t (WINAPI *pfnGetProcessMemoryInfo)(HANDLE, PPROCESS_MEMORY_COUNTERS, DWORD); - HMODULE m_hmPsapiDll = nullptr; - pfnGetProcessMemoryInfo m_GetProcessMemoryInfo = nullptr; - PROCESS_MEMORY_COUNTERS pcnt; + static HMODULE m_hmPsapiDll = nullptr; + static pfnGetProcessMemoryInfo m_GetProcessMemoryInfo = nullptr; + static PROCESS_MEMORY_COUNTERS pcnt; #else // (Unix) #include #endif @@ -77,17 +77,17 @@ size_t CServerDef::StatGet(SERV_STAT_TYPE i) const m_hmPsapiDll = LoadLibrary(TEXT("psapi.dll")); if (m_hmPsapiDll == nullptr) { - m_fPmemory = false; + sm_fHasMemoryInfo = false; g_Log.EventError(("Unable to load process information PSAPI.DLL library. Memory information will be not available.\n")); } else { -#ifndef _MSC_VER +#ifdef NON_MSVC_COMPILER #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wcast-function-type" #endif m_GetProcessMemoryInfo = reinterpret_cast(::GetProcAddress(m_hmPsapiDll,"GetProcessMemoryInfo")); -#ifndef _MSC_VER +#if NON_MSVC_COMPILER #pragma GCC diagnostic pop #endif } diff --git a/src/game/CWorldSearch.h b/src/game/CWorldSearch.h index 7a598c83b..c8da39010 100644 --- a/src/game/CWorldSearch.h +++ b/src/game/CWorldSearch.h @@ -5,7 +5,7 @@ #include "../common/CRect.h" /* -#ifdef _MSC_VER +#ifdef MSVC_COMPILER # pragma warning(push) # pragma warning(disable : 4244) # pragma warning(disable : 4267) @@ -14,7 +14,7 @@ #include -#ifdef _MSC_VER +#ifdef MSVC_COMPILER # pragma warning(pop) #endif */ diff --git a/src/game/CWorldTicker.h b/src/game/CWorldTicker.h index 31d84a808..22729e3b2 100644 --- a/src/game/CWorldTicker.h +++ b/src/game/CWorldTicker.h @@ -39,14 +39,14 @@ /* End of phmap.h inclusion */ /* Include btree.h */ -#ifdef __GNUC__ +#if NON_MSVC_COMPILER #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant" #endif #include -#ifdef __GNUC__ +#if NON_MSVC_COMPILER #pragma GCC diagnostic pop #endif /* End of btree.h inclusion */ diff --git a/src/game/spheresvr.cpp b/src/game/spheresvr.cpp index 176ce878d..5b989a4de 100644 --- a/src/game/spheresvr.cpp +++ b/src/game/spheresvr.cpp @@ -72,7 +72,7 @@ GlobalInitializer::GlobalInitializer() //--- Exception handling // Set exception catcher? -#if defined(_WIN32) && defined(_MSC_VER) && !defined(_NIGHTLYBUILD) +#if defined(MSVC_COMPILER) && !defined(_NIGHTLYBUILD) // We don't need an exception translator for the Debug build, since that build would, generally, be used with a debugger. // We don't want that for Release build either because, in order to call _set_se_translator, we should set the /EHa // compiler flag, which slows down code a bit. diff --git a/src/game/uo_files/CUOHuesRec.h b/src/game/uo_files/CUOHuesRec.h index 711fa565c..904cf4558 100644 --- a/src/game/uo_files/CUOHuesRec.h +++ b/src/game/uo_files/CUOHuesRec.h @@ -9,7 +9,7 @@ #include "../../common/common.h" // All these structures must be byte packed. -#if defined(_WIN32) && defined(_MSC_VER) +#ifdef MSVC_COMPILER // Microsoft dependant pragma #pragma pack(1) #define PACK_NEEDED @@ -31,7 +31,7 @@ struct CUOHuesRec // Turn off structure packing. -#if defined(_WIN32) && defined(_MSC_VER) +#ifdef MSVC_COMPILER #pragma pack() #else #undef PACK_NEEDED diff --git a/src/game/uo_files/CUOIndexRec.h b/src/game/uo_files/CUOIndexRec.h index 2ce39725b..8cd663ae9 100644 --- a/src/game/uo_files/CUOIndexRec.h +++ b/src/game/uo_files/CUOIndexRec.h @@ -10,7 +10,7 @@ // All these structures must be byte packed. -#if defined(_WIN32) && defined(_MSC_VER) +#ifdef MSVC_COMPILER // Microsoft dependant pragma #pragma pack(1) #define PACK_NEEDED @@ -53,7 +53,7 @@ struct CUOIndexRec // Turn off structure packing. -#if defined(_WIN32) && defined(_MSC_VER) +#ifdef MSVC_COMPILER #pragma pack() #else #undef PACK_NEEDED diff --git a/src/game/uo_files/CUOItemTypeRec.h b/src/game/uo_files/CUOItemTypeRec.h index 21d4febae..f8c843560 100644 --- a/src/game/uo_files/CUOItemTypeRec.h +++ b/src/game/uo_files/CUOItemTypeRec.h @@ -9,7 +9,7 @@ #include "../../common/common.h" // All these structures must be byte packed. -#if defined(_WIN32) && defined(_MSC_VER) +#ifdef MSVC_COMPILER // Microsoft dependant pragma #pragma pack(1) #define PACK_NEEDED @@ -56,7 +56,7 @@ struct CUOItemTypeRec_HS // Turn off structure packing. -#if defined(_WIN32) && defined(_MSC_VER) +#ifdef MSVC_COMPILER #pragma pack() #else #undef PACK_NEEDED diff --git a/src/game/uo_files/CUOMapBlock.h b/src/game/uo_files/CUOMapBlock.h index 9bc9e9075..6774473b1 100644 --- a/src/game/uo_files/CUOMapBlock.h +++ b/src/game/uo_files/CUOMapBlock.h @@ -10,7 +10,7 @@ #include "uofiles_macros.h" // All these structures must be byte packed. -#if defined(_WIN32) && defined(_MSC_VER) +#ifdef MSVC_COMPILER // Microsoft dependant pragma #pragma pack(1) #define PACK_NEEDED @@ -32,7 +32,7 @@ struct CUOMapBlock // Turn off structure packing. -#if defined(_WIN32) && defined(_MSC_VER) +#ifdef MSVC_COMPILER #pragma pack() #else #undef PACK_NEEDED diff --git a/src/game/uo_files/CUOMapMeter.h b/src/game/uo_files/CUOMapMeter.h index 94350d817..46d664ec5 100644 --- a/src/game/uo_files/CUOMapMeter.h +++ b/src/game/uo_files/CUOMapMeter.h @@ -9,7 +9,7 @@ #include "../../common/common.h" // All these structures must be byte packed. -#if defined(_WIN32) && defined(_MSC_VER) +#ifdef MSVC_COMPILER // Microsoft dependant pragma #pragma pack(1) #define PACK_NEEDED @@ -32,7 +32,7 @@ struct CUOMapMeter // Turn off structure packing. -#if defined(_WIN32) && defined(_MSC_VER) +#ifdef MSVC_COMPILER #pragma pack() #else #undef PACK_NEEDED diff --git a/src/game/uo_files/CUOMultiItemRec.h b/src/game/uo_files/CUOMultiItemRec.h index 421da7c98..da45d75be 100644 --- a/src/game/uo_files/CUOMultiItemRec.h +++ b/src/game/uo_files/CUOMultiItemRec.h @@ -10,7 +10,7 @@ #include "uofiles_enums_itemid.h" // All these structures must be byte packed. -#if defined(_WIN32) && defined(_MSC_VER) +#ifdef MSVC_COMPILER // Microsoft dependant pragma #pragma pack(1) #define PACK_NEEDED @@ -50,7 +50,7 @@ struct CUOMultiItemRec_HS // (Multi.mul, High Seas+) // Turn off structure packing. -#if defined(_WIN32) && defined(_MSC_VER) +#ifdef MSVC_COMPILER #pragma pack() #else #undef PACK_NEEDED diff --git a/src/game/uo_files/CUOStaticItemRec.h b/src/game/uo_files/CUOStaticItemRec.h index 69776f73f..86925e1ee 100644 --- a/src/game/uo_files/CUOStaticItemRec.h +++ b/src/game/uo_files/CUOStaticItemRec.h @@ -10,7 +10,7 @@ #include "uofiles_enums_itemid.h" // All these structures must be byte packed. -#if defined(_WIN32) && defined(_MSC_VER) +#ifdef MSVC_COMPILER // Microsoft dependant pragma #pragma pack(1) #define PACK_NEEDED @@ -39,7 +39,7 @@ struct CUOStaticItemRec // Turn off structure packing. -#if defined(_WIN32) && defined(_MSC_VER) +#ifdef MSVC_COMPILER #pragma pack() #else #undef PACK_NEEDED diff --git a/src/game/uo_files/CUOTerrainTypeRec.h b/src/game/uo_files/CUOTerrainTypeRec.h index 8e3413bad..e97b19354 100644 --- a/src/game/uo_files/CUOTerrainTypeRec.h +++ b/src/game/uo_files/CUOTerrainTypeRec.h @@ -9,7 +9,7 @@ #include "../../common/common.h" // All these structures must be byte packed. -#if defined(_WIN32) && defined(_MSC_VER) +#ifdef MSVC_COMPILER // Microsoft dependant pragma #pragma pack(1) #define PACK_NEEDED @@ -51,7 +51,7 @@ struct CUOTerrainTypeRec_HS // Turn off structure packing. -#if defined(_WIN32) && defined(_MSC_VER) +#ifdef MSVC_COMPILER #pragma pack() #else #undef PACK_NEEDED diff --git a/src/game/uo_files/CUOVersionBlock.h b/src/game/uo_files/CUOVersionBlock.h index 09b2ac2e6..e50e75e4e 100644 --- a/src/game/uo_files/CUOVersionBlock.h +++ b/src/game/uo_files/CUOVersionBlock.h @@ -13,7 +13,7 @@ // All these structures must be byte packed. -#if defined(_WIN32) && defined(_MSC_VER) +#ifdef MSVC_COMPILER // Microsoft dependant pragma #pragma pack(1) #define PACK_NEEDED @@ -59,7 +59,7 @@ struct CUOVersionBlock // Turn off structure packing. -#if defined(_WIN32) && defined(_MSC_VER) +#ifdef MSVC_COMPILER #pragma pack() #else #undef PACK_NEEDED diff --git a/src/network/CNetworkOutput.cpp b/src/network/CNetworkOutput.cpp index 3abf84731..17c8fb1c5 100644 --- a/src/network/CNetworkOutput.cpp +++ b/src/network/CNetworkOutput.cpp @@ -16,7 +16,7 @@ * void SendCompleted_Winsock Winsock event handler for when async operation completes * ***************************************************************************/ -void CALLBACK SendCompleted_Winsock(DWORD dwError, DWORD cbTransferred, LPWSAOVERLAPPED lpOverlapped, DWORD dwFlags) +static void CALLBACK SendCompleted_Winsock(DWORD dwError, DWORD cbTransferred, LPWSAOVERLAPPED lpOverlapped, DWORD dwFlags) { UnreferencedParameter(dwFlags); ADDTOCALLSTACK("SendCompleted_Winsock"); diff --git a/src/network/net_datatypes.h b/src/network/net_datatypes.h index e6633453c..04a5cd44b 100644 --- a/src/network/net_datatypes.h +++ b/src/network/net_datatypes.h @@ -18,7 +18,7 @@ // All these structures must be byte packed. -#if defined(_WIN32) && defined(_MSC_VER) +#if defined(MSVC_COMPILER) // Microsoft dependant pragma #pragma pack(1) #define PACK_NEEDED @@ -81,7 +81,7 @@ struct ndword // Turn off structure packing. -#if defined(_WIN32) && defined(_MSC_VER) +#if defined(_WIN32) && defined(MSVC_COMPILER) #pragma pack() #endif diff --git a/src/network/packet.cpp b/src/network/packet.cpp index 10adbb25a..f524c263f 100644 --- a/src/network/packet.cpp +++ b/src/network/packet.cpp @@ -815,12 +815,12 @@ void Packet::readStringASCII(wchar* buffer, uint length, bool includeNull) char* bufferReal = new char[(size_t)length + 1](); readStringASCII(bufferReal, length, includeNull); -#ifdef _MSC_VER +# ifdef MSVC_RUNTIME size_t aux; mbstowcs_s(&aux, buffer, length + 1, bufferReal, length); -#else +# else mbstowcs(buffer, bufferReal, length); -#endif +# endif delete[] bufferReal; #else diff --git a/src/resources/SphereSvr.rc b/src/resources/SphereSvr.rc index 7d99d47b0..4d087d7d9 100644 --- a/src/resources/SphereSvr.rc +++ b/src/resources/SphereSvr.rc @@ -13,14 +13,14 @@ # define WIN32_LEAN_AND_MEAN // include just windows.h without the other winapi headers, we'll add them manually when needed # endif -# ifdef _MSC_VER +# if defined(_MSC_VER) && !defined(__clang__) // Workaround to a possible VS compiler bug: instead of complaining if a macro expands to a "defined" macro, // it complains if a define macro contains the words "defined" in its name... # pragma warning(push) # pragma warning(disable: 5105) # endif # include -# ifdef _MSC_VER +# if defined(_MSC_VER) && !defined(__clang__) # pragma warning(pop) # endif @@ -89,12 +89,12 @@ IDR_MAINFRAME ICON "spheresvr.ico" // #ifdef APSTUDIO_INVOKED -1 TEXTINCLUDE +1 TEXTINCLUDE BEGIN "win_resource.h\0" END -2 TEXTINCLUDE +2 TEXTINCLUDE BEGIN "\r\n" "\0" diff --git a/src/resources/resource.h b/src/resources/resource.h deleted file mode 100644 index b406120f2..000000000 --- a/src/resources/resource.h +++ /dev/null @@ -1,43 +0,0 @@ -//{{NO_DEPENDENCIES}} -// File di inclusione generato con Microsoft Visual C++. -// Utilizzato da SphereSvr.rc -// -#define IDC_STATIC 0 -#define IDR_MAINFRAME 100 -#define IDR_ABOUT_BOX 101 -#define IDM_POP_TRAY 102 -#define IDM_POP_LOG 103 -#define IDC_STAT_STATS 201 -#define IDC_STAT_CLIENTS 202 -#define IDC_O_LOG_LEVEL 250 -#define IDC_O_LOG_CLIENTS 251 -#define IDC_O_LOG_GM_CMDS 252 -#define IDC_O_LOG_GM_PAGES 253 -#define IDC_O_LOG_SPEAK 254 -#define IDM_STATUS 528 -#define IDM_RESTORE 544 -#define IDM_MINIMIZE 560 -#define IDM_EDIT_COPY 580 -#define IDM_EXIT 582 -#define IDC_ABOUT_VERSION 1117 -#define IDC_ABOUT_COMPILER 1118 -#define IDC_ABOUT_MENASOFT_LINK 1119 -#define IDC_ABOUT_SPHERE_LINK 1120 -#define IDC_SETUP_PORT 4020 -#define IDC_SETUP_SCRIPTS 4021 -#define IDC_SETUP_SAVE 4022 -#define IDC_SETUP_LOG 4023 -#define IDC_SETUP_NAME 4024 -#define IDM_RESYNC_PAUSE 32784 - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_3D_CONTROLS 1 -#define _APS_NEXT_RESOURCE_VALUE 161 -#define _APS_NEXT_COMMAND_VALUE 32785 -#define _APS_NEXT_CONTROL_VALUE 4026 -#define _APS_NEXT_SYMED_VALUE 210 -#endif -#endif diff --git a/src/sphere/ntservice.cpp b/src/sphere/ntservice.cpp index 88857c81c..a346d593b 100644 --- a/src/sphere/ntservice.cpp +++ b/src/sphere/ntservice.cpp @@ -450,7 +450,7 @@ void CNTService::CmdMainStart() // FUNCTION: main() // ///////////////////////////////////////////////////////////////////////////////////// -#ifdef _MSC_VER +#ifdef MSVC_COMPILER int WINAPI WinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPSTR lpCmdLine, _In_ int nCmdShow) #else int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) diff --git a/src/sphere/ntservice.h b/src/sphere/ntservice.h index a064e41ab..124ffa518 100644 --- a/src/sphere/ntservice.h +++ b/src/sphere/ntservice.h @@ -8,14 +8,14 @@ #ifdef _WIN32 +#include "../common/common.h" -#ifndef _MSC_VER +#ifdef NON_MSVC_COMPILER #include #else #include // exception handling info. -#endif // _MSC_VER +#endif // NON_MSVC_COMPILER -#include "../common/common.h" extern class CNTService diff --git a/src/sphere/ntwindow.h b/src/sphere/ntwindow.h index 42d7730e0..2c4b75d18 100644 --- a/src/sphere/ntwindow.h +++ b/src/sphere/ntwindow.h @@ -23,10 +23,10 @@ extern struct CNTWindow : public AbstractSphereThread, public CSWindow, public C int nCmdShow; } _NTWInitParams; - virtual void onStart(); - virtual void terminate(bool ended); + virtual void onStart() override; + virtual void terminate(bool ended) override; virtual bool shouldExit() noexcept override; - virtual void tick(); + virtual void tick() override; bool NTWindow_Init(HINSTANCE hInstance, LPTSTR lpCmdLinel, int nCmdShow); void NTWindow_ExitServer(); @@ -41,7 +41,7 @@ extern struct CNTWindow : public AbstractSphereThread, public CSWindow, public C std::shared_mutex _mutexWindowTitle; void exitActions(); - + public: class CAboutDlg : public CDialogBase // CNTWindow::CAboutDlg { From ded506cde3f913ebd6d80567cbf4b1de299016f1 Mon Sep 17 00:00:00 2001 From: cbnolok Date: Thu, 3 Oct 2024 13:31:47 +0200 Subject: [PATCH 16/32] Updated .clang-format and .gitignore. --- .clang-format | 115 ++++++++++++++++++++++++-------------------------- .gitignore | 1 + 2 files changed, 56 insertions(+), 60 deletions(-) diff --git a/.clang-format b/.clang-format index 7e32248d7..1cc6ca616 100644 --- a/.clang-format +++ b/.clang-format @@ -1,30 +1,35 @@ +# Based on LLVM style with C++20 support BasedOnStyle: LLVM Language: Cpp Standard: c++20 + +# Tab and indent settings TabWidth: 4 IndentWidth: 4 UseTab: Never ColumnLimit: 160 +# Text line management #LineEndingStyle: LF -#MaxEmptyLinesToKeep: 3 +MaxEmptyLinesToKeep: 2 +InsertNewlineAtEOF: true -##-- Alignment -AlignAfterOpenBracket: AlwaysBreak +# Alignment settings +AlignAfterOpenBracket: DontAlign AlignConsecutiveAssignments: true AlignConsecutiveDeclarations: false #AlignConsecutiveTableGenDefinitionColons: # Enabled: true # AcrossEmptyLines: true # AcrossComments: false -AlignEscapedNewlines: Left # LeftWithLastLine # Right +AlignEscapedNewlines: Left AlignTrailingComments: Kind: Always OverEmptyLines: 1 DerivePointerAlignment: false PointerAlignment: Right -##-- Single line statements +# Single-line statements settings AllowShortBlocksOnASingleLine: false AllowShortCaseLabelsOnASingleLine: false AllowShortFunctionsOnASingleLine: None @@ -32,8 +37,8 @@ AllowShortIfStatementsOnASingleLine: Never AllowShortLambdasOnASingleLine: Inline AllowShortLoopsOnASingleLine: false -##-- Braces -BreakBeforeBraces: Custom #Allman +# Braces and wrapping settings +BreakBeforeBraces: Custom BraceWrapping: AfterCaseLabel: true AfterClass: false @@ -52,88 +57,78 @@ BraceWrapping: SplitEmptyNamespace: false Cpp11BracedListStyle: false -##-- Line breaks +# Line breaks and wrapping settings +#AllowAllParametersOfDeclarationOnNextLine: true #AllowBreakBeforeNoexceptSpecifier: OnlyWithParen -AlwaysBreakAfterDefinitionReturnType: All -AlwaysBreakAfterReturnType: None +AlwaysBreakAfterDefinitionReturnType: None # Keep return type on the same line if possible +AlwaysBreakAfterReturnType: None # Default value AlwaysBreakBeforeMultilineStrings: true -BreakAfterAttributes: Always AlwaysBreakTemplateDeclarations: true -BreakAfterJavaFieldAnnotations: false -BreakBeforeBinaryOperators: None +BreakAfterAttributes: Always +BreakBeforeBinaryOperators: None # Default value: No line break before binary operators BreakBeforeConceptDeclarations: Always BreakConstructorInitializers: AfterColon -#BreakInheritanceList: AfterColon -BreakBeforeTernaryOperators: false +BreakBeforeTernaryOperators: false # Default value BreakConstructorInitializersBeforeComma: true -BreakStringLiterals: false +#BreakInheritanceList: AfterColon +BreakStringLiterals: false # Default value +PackConstructorInitializers: NextLineOnly +PenaltyReturnTypeOnItsOwnLine: 200 # Prefer keeping return type on the same line if possible -##-- Indentation +# Indentation settings +#AccessModifierOffset: -4 +IndentAccessModifiers: false IndentCaseBlocks: false IndentCaseLabels: true IndentExternBlock: AfterExternBlock IndentGotoLabels: true IndentPPDirectives: AfterHash +IndentWrappedFunctionNames: false LambdaBodyIndentation: Signature NamespaceIndentation: Inner -##-- Spaces in/between statements/etc -MaxEmptyLinesToKeep: 2 -SeparateDefinitionBlocks: Always -SpaceAfterCStyleCast: false -SpaceAfterTemplateKeyword: false +# Spaces around statements settings +SpaceAfterCStyleCast: false # Default value +SpaceAfterTemplateKeyword: false # Default value #SpaceAroundPointerQualifiers: Left SpaceBeforeAssignmentOperators: true SpaceBeforeCpp11BracedList: true SpaceBeforeCtorInitializerColon: true SpaceBeforeInheritanceColon: true SpaceBeforeParens: ControlStatements -SpaceInEmptyParentheses: false -SpacesInAngles: false -SpacesInCStyleCastParentheses: false -SpacesInContainerLiterals: false -SpacesInParentheses: false -SpacesInSquareBrackets: false +SpaceInEmptyParentheses: false # Default value +SpacesInAngles: false # Default value +SpacesInCStyleCastParentheses: false # Default value +SpacesInContainerLiterals: false # Default value +SpacesInParentheses: false # Default value +SpacesInSquareBrackets: false # Default value - -##-- Code sections/blocks +# Macros settings #MacroBlockBegin: [regex -> EXC_TRY...] #MacroBlockEnd: +#StatementMacros: [-> ASSERT?] + +# Scopes settings FixNamespaceComments: true ShortNamespaceLines: 2 -#StatementMacros: [-> ASSERT?] -##-- Misc -AllowAllParametersOfDeclarationOnNextLine: true -AccessModifierOffset: -4 -BinPackArguments: false -BinPackParameters: false -ConstructorInitializerAllOnOneLineOrOnePerLine: false -DisableFormat: false -ExperimentalAutoDetectBinPacking: false -InsertNewlineAtEOF: true -KeepEmptyLinesAtTheStartOfBlocks: false +# Miscellaneous settings +SeparateDefinitionBlocks: Always ReflowComments: false -#-- Include order -#IncludeIsMainRegex: '$?' +# Include order #IncludeBlocks: Regroup +#IncludeIsMainRegex: '$?' IncludeCategories: #TODO: main include! - # Headers in "" with .h extension. - - Regex: '"([A-Za-z0-9\/-_])+\.h"' - Priority: 1 - # Headers in "" with .hpp extension. - - Regex: '"([A-Za-z0-9\/-_])+\.hpp"' - Priority: 2 - - # Headers in <> with .h extension. - - Regex: '<([A-Za-z0-9\/-_])+\.h>' - Priority: 10 - # Headers in <> with .hpp extension. - - Regex: '<([A-Za-z0-9\/-_])+\.hpp>' - Priority: 20 - # Headers in <> without extension. - - Regex: '<([A-Za-z0-9\/-_])+>' - Priority: 30 -SortIncludes: false #CaseSensitive + - Regex: '"([A-Za-z0-9\/-_])+\.h"' + Priority: 1 + - Regex: '"([A-Za-z0-9\/-_])+\.hpp"' + Priority: 2 + - Regex: '<([A-Za-z0-9\/-_])+\.h>' + Priority: 10 + - Regex: '<([A-Za-z0-9\/-_])+\.hpp>' + Priority: 20 + - Regex: '<([A-Za-z0-9\/-_])+>' + Priority: 30 +SortIncludes: false diff --git a/.gitignore b/.gitignore index 8fde82f30..a21d5394c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ # Ignore folders +/.cache /.git /.vscode *.vshistory* From a043502947a0330f9f76cfd41fd7f136ba566771 Mon Sep 17 00:00:00 2001 From: cbnolok Date: Thu, 3 Oct 2024 14:34:29 +0200 Subject: [PATCH 17/32] Fixed compilation errors. Made more (easily) cross-platform the AbstractThread code (looking also at BSD). --- CMakeLists.txt | 5 ++++- cmake/CompilerFlagsChecker.cmake | 18 +++++++++++++++++- lib/bcrypt/bcrypt/wrapper.c | 2 +- src/common/CException.cpp | 2 ++ src/common/CException.h | 4 ++-- src/common/sphere_library/sptr.h | 2 +- src/common/sphere_library/stypecast.h | 9 +++++---- src/sphere/threads.cpp | 27 ++++++++++++--------------- src/sphere/threads.h | 11 +++++++---- 9 files changed, 51 insertions(+), 29 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9554694a9..491c597a2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -99,7 +99,6 @@ set(CMAKE_CXX_FLAGS_RELEASE "") set(CMAKE_EXE_LINKER_FLAGS "") set(CMAKE_EXE_LINKER_FLAGS_DEBUG "") -set(CMAKE_EXE_LINKER_FLAGS_NIGHTLY "") set(CMAKE_EXE_LINKER_FLAGS_RELEASE "") ]] # Example: using MSVC, /RTC1 is globally added (all projects) to DEBUG builds. It's mostly fine, except in some cases where we don't want it... @@ -107,6 +106,10 @@ set(CMAKE_EXE_LINKER_FLAGS_RELEASE "") #STRING (REGEX REPLACE "/RTC(su|[1su])" "" CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}") #STRING (REGEX REPLACE "/RTC(su|[1su])" "" CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG}") +# Also, it fails to create those predefined flags, which it needs, for custom build types (e.g. Nightly). +set(CMAKE_EXE_LINKER_FLAGS_NIGHTLY "") + + set(is_win32_app_linker) if(WIN32 AND NOT ${WIN32_SPAWN_CONSOLE}) set(is_win32_app_linker WIN32) # if not set, it defaults to console subsystem diff --git a/cmake/CompilerFlagsChecker.cmake b/cmake/CompilerFlagsChecker.cmake index 2cd570296..7bfb40fe0 100644 --- a/cmake/CompilerFlagsChecker.cmake +++ b/cmake/CompilerFlagsChecker.cmake @@ -16,6 +16,15 @@ if(NOT MSVC) ) list(APPEND base_compiler_options_warning -Werror;-Wall;-Wextra;-Wpedantic) + # Linker flags (warnings) + #check_cxx_compiler_flag("-Wl,--fatal-warnings" COMP_LINKER_HAS_FATAL_WARNINGS_V1) + #check_cxx_compiler_flag("-Wl,-fatal-warnings" COMP_LINKER_HAS_FATAL_WARNINGS_V2) + if(CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang") + set(COMP_LINKER_HAS_FATAL_WARNINGS_V2 TRUE) + else() + set(COMP_LINKER_HAS_FATAL_WARNINGS_V1 TRUE) + endif() + # Compiler option flags. Common to both compilers, but older versions might not support the following. #check_cxx_compiler_flag("" COMP_HAS_) @@ -197,6 +206,13 @@ endif() # ---- GCC/Clang if(NOT MSVC) + if(COMP_LINKER_HAS_FATAL_WARNINGS_V1) + list(APPEND checked_linker_options_all "-Wl,--fatal-warnings") + endif() + if(COMP_LINKER_HAS_FATAL_WARNINGS_V2) + list(APPEND checked_linker_options_all "-Wl,-fatal_warnings") + endif() + if(COMP_HAS_FNO_EXPENSIVE_OPTIMIZATIONS) list(APPEND checked_compiler_options "-fno-expensive-optimizations") endif() @@ -452,7 +468,7 @@ if(NOT MSVC) ${checked_compiler_warnings_disabled} ) - list(APPEND list_explicit_linker_options_all ${checked_linker_options_all};-pthread;-dynamic;-Wl,--fatal-warnings) + list(APPEND list_explicit_linker_options_all ${checked_linker_options_all};-pthread;-dynamic) #string(JOIN " " string_checked_compiler_options_all ${list_checked_compiler_options_all}) #set(string_checked_compiler_options_all CACHE INTERNAL STRING) diff --git a/lib/bcrypt/bcrypt/wrapper.c b/lib/bcrypt/bcrypt/wrapper.c index 6a3503f5b..fe20e7577 100644 --- a/lib/bcrypt/bcrypt/wrapper.c +++ b/lib/bcrypt/bcrypt/wrapper.c @@ -50,7 +50,7 @@ extern struct crypt_data _ufc_foobar; char* mystrdup(const char* s) { const size_t len = strlen(s); - char* p = malloc(len) + 1; + char* p = (char*)(malloc(len + 1)); if (p) { //strcpy(p, s); diff --git a/src/common/CException.cpp b/src/common/CException.cpp index 683ae0239..5dcd8beac 100644 --- a/src/common/CException.cpp +++ b/src/common/CException.cpp @@ -77,12 +77,14 @@ static bool IsAbortImmediate() noexcept } #endif +[[noreturn]] void RaiseRecoverableAbort() { EXC_NOTIFY_DEBUGGER; SetAbortImmediate(false); std::abort(); } +[[noreturn]] void RaiseImmediateAbort() { EXC_NOTIFY_DEBUGGER; diff --git a/src/common/CException.h b/src/common/CException.h index a767cc666..99543be87 100644 --- a/src/common/CException.h +++ b/src/common/CException.h @@ -28,9 +28,9 @@ void SetExceptionTranslator(); void NotifyDebugger(); void SetAbortImmediate(bool on) noexcept; -bool AbortImmediate() noexcept; - +[[noreturn]] void RaiseRecoverableAbort(); +[[noreturn]] void RaiseImmediateAbort(); diff --git a/src/common/sphere_library/sptr.h b/src/common/sphere_library/sptr.h index ee34faaa6..ce9b396cc 100644 --- a/src/common/sphere_library/sptr.h +++ b/src/common/sphere_library/sptr.h @@ -3,7 +3,7 @@ // On Windows, Clang with MSVC runtime defines _MSC_VER! (But also __clang__). #ifndef NON_MSVC_COMPILER -# if !defined(_MSC_VER) || !defined(__clang__) +# if !defined(_MSC_VER) || defined(__clang__) # define NON_MSVC_COMPILER 1 # endif #endif diff --git a/src/common/sphere_library/stypecast.h b/src/common/sphere_library/stypecast.h index d367c41f1..1331a4a1e 100644 --- a/src/common/sphere_library/stypecast.h +++ b/src/common/sphere_library/stypecast.h @@ -499,7 +499,7 @@ constexpr uint32 usize_narrow_u32(const size_t source_val) noexcept #if SIZE_MAX == UINT64_MAX return n64_narrow_n32(source_val); #elif SIZE_MAX == UINT32_MAX - return a; + return source_val; #else # error "size_t is neither 8 nor 4 bytes?" #endif @@ -677,7 +677,7 @@ template int64 i64_from_u64_checked(T, bool) = delete; // disable i #if SIZE_MAX == UINT64_MAX return n64_narrow_n8_checked(source_val, should_assert); #elif SIZE_MAX == UINT32_MAX - return n32_narrow_n8_checked(source_val); + return n32_narrow_n8_checked(source_val, should_assert); #else # error "size_t is neither 8 nor 4 bytes?" #endif @@ -691,7 +691,7 @@ template int8 i8_from_usize_checked(T, bool) = delete; // disable i #if SIZE_MAX == UINT64_MAX return n64_narrow_n16_checked(source_val, should_assert); #elif SIZE_MAX == UINT32_MAX - return n32_narrow_n16_checked(source_val); + return n32_narrow_n16_checked(source_val, should_assert); #else # error "size_t is neither 8 nor 4 bytes?" #endif @@ -704,7 +704,7 @@ template int16 i16_from_usize_checked(T, bool) = delete; // disable #if SIZE_MAX == UINT64_MAX return i32_from_u32_clamping(n64_narrow_n32_checked(source_val, should_assert)); #elif SIZE_MAX == UINT32_MAX - return i32_from_u32_checked(n_alias_cast(source_val)); + return i32_from_u32_checked(n_alias_cast(source_val), should_assert); #else # error "size_t is neither 8 nor 4 bytes?" #endif @@ -717,6 +717,7 @@ template int32 i32_from_usize_checked(T, bool) = delete; // disable #if SIZE_MAX == UINT64_MAX return i64_from_u64_checked(n_alias_cast(source_val), should_assert); #elif SIZE_MAX == UINT32_MAX + (void)should_assert; return static_cast(source_val); // For sure it will fit #else # error "size_t is neither 8 nor 4 bytes?" diff --git a/src/sphere/threads.cpp b/src/sphere/threads.cpp index 77dba0d3b..204ed2e28 100644 --- a/src/sphere/threads.cpp +++ b/src/sphere/threads.cpp @@ -61,8 +61,7 @@ IThread::IThread() noexcept : // This is needed to prevent weak-vtables warning (puts the vtable in this translation unit instead of every translation unit) IThread::~IThread() noexcept = default; -#ifdef _WIN32 -/* +#if defined(_WIN32) && defined(MSVC_COMPILER) #pragma pack(push, 8) typedef struct tagTHREADNAME_INFO { @@ -72,12 +71,9 @@ typedef struct tagTHREADNAME_INFO DWORD dwFlags; } THREADNAME_INFO; #pragma pack(pop) -*/ -#ifdef MSVC_COMPILER static constexpr DWORD MS_VC_EXCEPTION = 0x406D1388; #endif -#endif void IThread::setThreadName(const char* name) { @@ -104,7 +100,7 @@ void IThread::setThreadName(const char* name) __except(EXCEPTION_EXECUTE_HANDLER) { } - #endif + #endif // MSVC_COMPILER #elif defined(__APPLE__) // Mac pthread_setname_np(name_trimmed); #elif !defined(_BSD) // Linux @@ -438,7 +434,6 @@ AbstractThread::AbstractThread(const char *name, IThread::Priority priority) : } m_threadSystemId = 0; Str_CopyLimitNull(m_name, name, sizeof(m_name)); - m_handle = SPHERE_THREADT_NULL; m_hangCheck = 0; _thread_selfTerminateAfterThisTick = true; m_terminateRequested = true; @@ -480,14 +475,16 @@ void AbstractThread::start() pthread_attr_t threadAttr; pthread_attr_init(&threadAttr); pthread_attr_setdetachstate(&threadAttr, PTHREAD_CREATE_DETACHED); - int result = pthread_create( &m_handle, &threadAttr, &runner, this ); + spherethread_t threadHandle{}; + int result = pthread_create( &threadHandle, &threadAttr, &runner, this ); pthread_attr_destroy(&threadAttr); if (result != 0) { - m_handle = 0; + m_handle = std::nullopt; throw CSError(LOGL_FATAL, 0, "Unable to spawn a new thread"); } + m_handle = threadHandle; #endif m_terminateEvent.reset(); @@ -506,10 +503,10 @@ void AbstractThread::terminate(bool ended) if (wasCurrentThread == false) { #ifdef _WIN32 - TerminateThread(m_handle, 0); - CloseHandle(m_handle); + TerminateThread(m_handle.value(), 0); + CloseHandle(m_handle.value()); #else - pthread_cancel(m_handle); // IBM say it so + pthread_cancel(m_handle.value()); // IBM say it so #endif } } @@ -517,7 +514,7 @@ void AbstractThread::terminate(bool ended) // Common things ThreadHolder::get().remove(this); m_threadSystemId = 0; - m_handle = SPHERE_THREADT_NULL; + m_handle = std::nullopt; // let everyone know we have been terminated m_terminateEvent.set(); @@ -650,7 +647,7 @@ SPHERE_THREADENTRY_RETNTYPE AbstractThread::runner(void *callerThread) bool AbstractThread::isActive() const { - return (m_handle != SPHERE_THREADT_NULL); + return m_handle.has_value(); } void AbstractThread::waitForClose() @@ -686,7 +683,7 @@ bool AbstractThread::isCurrentThread() const noexcept #ifdef _WIN32 return (getId() == ::GetCurrentThreadId()); #else - return pthread_equal(m_handle,pthread_self()); + return m_handle.has_value() && pthread_equal(m_handle.value(), pthread_self()); #endif } diff --git a/src/sphere/threads.h b/src/sphere/threads.h index 3534efbd6..1a2fb0598 100644 --- a/src/sphere/threads.h +++ b/src/sphere/threads.h @@ -34,15 +34,14 @@ #define SPHERE_THREADT_NULL nullptr #else typedef pthread_t spherethread_t; -#ifdef __APPLE__ +# ifdef __APPLE__ typedef uint64_t threadid_t; -#else +# else typedef pthread_t threadid_t; #endif #define SPHERE_THREADENTRY_RETNTYPE void * #define SPHERE_THREADENTRY_CALLTYPE - #define SPHERE_THREADT_NULL 0 #endif class IThread; @@ -219,7 +218,11 @@ class AbstractThread : public IThread char m_name[30]; static int m_threadsAvailable; - spherethread_t m_handle; + // pthread_t type is opaque (platform-defined). It can be an integer, a struct, a ptr something. Memset is the safest and more portable way. + //spherethread_t m_handle; + // Or, since we need here an "invalid" value, just use optional. + std::optional m_handle; + uint m_hangCheck; Priority m_priority; uint m_tickPeriod; From 9b81b0eaccc558aeddef26f570545561bb64c7f3 Mon Sep 17 00:00:00 2001 From: cbnolok Date: Thu, 3 Oct 2024 17:11:14 +0200 Subject: [PATCH 18/32] Refactored threads.h, removing useless matrioska interface class IThread. --- src/common/sphere_library/sstringobjs.cpp | 2 +- src/common/sphere_library/stypecast.h | 60 +++++-- src/game/CServer.cpp | 13 +- src/game/CServerConfig.cpp | 20 +-- src/game/CServerConfig.h | 2 +- src/game/spheresvr.cpp | 8 +- src/network/CNetState.cpp | 2 +- src/network/CNetworkInput.cpp | 2 +- src/network/CNetworkManager.cpp | 4 +- src/network/CNetworkOutput.cpp | 6 +- src/network/CNetworkThread.cpp | 12 +- src/network/PingServer.cpp | 2 +- src/network/linuxev.cpp | 2 +- src/sphere/ProfileTask.cpp | 2 +- src/sphere/UnixTerminal.cpp | 2 +- src/sphere/asyncdb.cpp | 2 +- src/sphere/ntservice.cpp | 2 +- src/sphere/ntwindow.cpp | 4 +- src/sphere/threads.cpp | 209 ++++++++++------------ src/sphere/threads.h | 182 ++++++++----------- 20 files changed, 259 insertions(+), 279 deletions(-) diff --git a/src/common/sphere_library/sstringobjs.cpp b/src/common/sphere_library/sstringobjs.cpp index 951b88923..765aeb009 100644 --- a/src/common/sphere_library/sstringobjs.cpp +++ b/src/common/sphere_library/sstringobjs.cpp @@ -34,7 +34,7 @@ static tchar* getUnsafeStringBuffer() noexcept tchar* Str_GetTemp() noexcept { - IThread *pThreadState = ThreadHolder::get().current(); + AbstractThread *pThreadState = ThreadHolder::get().current(); if (pThreadState) return static_cast(pThreadState)->allocateBuffer(); return getUnsafeStringBuffer(); diff --git a/src/common/sphere_library/stypecast.h b/src/common/sphere_library/stypecast.h index 1331a4a1e..d4143ec2a 100644 --- a/src/common/sphere_library/stypecast.h +++ b/src/common/sphere_library/stypecast.h @@ -509,11 +509,12 @@ constexpr uint32 usize_narrow_u32(const size_t source_val) noexcept [[nodiscard]] inline uint32 usize_narrow_u32_checked(const size_t source_val, bool should_assert) { - if (should_assert) + if (should_assert) { ASSERT(source_val <= std::numeric_limits::max()); - else if (source_val > std::numeric_limits::max()) + } + else if (source_val > std::numeric_limits::max()) { detail_stypecast::LogEventWarnWrapper("[Internal] Narrowing conversion from size_t to 32 bits unsigned integer will overflow.\n"); - + } return usize_narrow_u32(source_val); } @@ -572,10 +573,13 @@ uint32 usize_narrow_u32_checked(const size_t source_val, bool should_assert) int8 i8_from_u8_checked(const uint8 source_val, bool should_assert) // not clamping/capping { const bool would_overflow = (source_val > (uint8)std::numeric_limits::max()); - if (should_assert) + if (should_assert) { ASSERT(!would_overflow); - else if (would_overflow) + } + else if (would_overflow) { detail_stypecast::LogEventWarnWrapper("[Internal] Narrowing conversion from 8 bits unsigned integer to 8 bits signed integer will overflow.\n"); + } + return static_cast(source_val); } template int8 i8_from_u8_checked(T, bool) = delete; // disable implicit type conversion for the inpuT source_valrgument @@ -584,10 +588,12 @@ template int8 i8_from_u8_checked(T, bool) = delete; // disable impl int16 i8_from_u16_checked(const uint16 source_val, bool should_assert) // not clamping/capping { const bool would_overflow = (source_val > (uint16)std::numeric_limits::max()); - if (should_assert) + if (should_assert) { ASSERT(!would_overflow); - else if (would_overflow) + } + else if (would_overflow) { detail_stypecast::LogEventWarnWrapper("[Internal] Narrowing conversion from 16 bits unsigned integer to 8 bits signed integer will overflow.\n"); + } return static_cast(source_val); } @@ -597,10 +603,12 @@ template int16 i8_from_u16_checked(T, bool) = delete; // disable im int16 i16_from_u16_checked(const uint16 source_val, bool should_assert) // not clamping/capping { const bool would_overflow = (source_val > (uint16)std::numeric_limits::max()); - if (should_assert) + if (should_assert) { ASSERT(!would_overflow); - else if (would_overflow) + } + else if (would_overflow) { detail_stypecast::LogEventWarnWrapper("[Internal] Narrowing conversion from 16 bits unsigned integer to 16 bits signed integer will overflow.\n"); + } return static_cast(source_val); } @@ -610,10 +618,12 @@ template int16 i16_from_u16_checked(T, bool) = delete; // disable i int16 i16_from_u32_checked(const uint32 source_val, bool should_assert) // not clamping/capping { const bool would_overflow = (source_val > (uint32)std::numeric_limits::max()); - if (should_assert) + if (should_assert) { ASSERT(!would_overflow); - else if (would_overflow) + } + else if (would_overflow) { detail_stypecast::LogEventWarnWrapper("[Internal] Narrowing conversion from 32 bits unsigned integer to 16 bits signed integer will overflow.\n"); + } return static_cast(source_val); } @@ -623,10 +633,13 @@ template int16 i16_from_u32_checked(T, bool) = delete; // disable i int16 i16_from_u64_checked(const uint64 source_val, bool should_assert) // not clamping/capping { const bool would_overflow = (source_val > (uint64)std::numeric_limits::max()); - if (should_assert) + if (should_assert) { ASSERT(!would_overflow); - else if (would_overflow) + } + else if (would_overflow) { detail_stypecast::LogEventWarnWrapper("[Internal] Narrowing conversion from 64 bits unsigned integer to 16 bits signed integer will overflow.\n"); + } + return static_cast(source_val); } template int16 i16_from_u64_checked(T, bool) = delete; // disable implicit type conversion for the inpuT source_valrgument @@ -636,10 +649,13 @@ template int16 i16_from_u64_checked(T, bool) = delete; // disable i int32 i32_from_u32_checked(const uint32 source_val, bool should_assert) // not clamping/capping { const bool would_overflow = (source_val > (uint32)std::numeric_limits::max()); - if (should_assert) + if (should_assert) { ASSERT(!would_overflow); - else if (would_overflow) + } + else if (would_overflow) { detail_stypecast::LogEventWarnWrapper("[Internal] Narrowing conversion from 32 bits unsigned integer to 32 bits signed integer will overflow.\n"); + } + return static_cast(source_val); } template int32 i32_from_u32_checked(T, bool) = delete; // disable implicit type conversion for the inpuT source_valrgument @@ -648,10 +664,13 @@ template int32 i32_from_u32_checked(T, bool) = delete; // disable i int32 i32_from_u64_checked(const uint64 source_val, bool should_assert) // not clamping/capping { const bool would_overflow = (source_val > (uint64)std::numeric_limits::max()); - if (should_assert) + if (should_assert) { ASSERT(!would_overflow); - else if (would_overflow) + } + else if (would_overflow) { detail_stypecast::LogEventWarnWrapper("[Internal] Narrowing conversion from 64 bits unsigned integer to 32 bits signed integer will overflow.\n"); + } + return static_cast(source_val); } template int32 i32_from_u64_checked(T, bool) = delete; // disable implicit type conversion for the inpuT source_valrgument @@ -661,10 +680,13 @@ template int32 i32_from_u64_checked(T, bool) = delete; // disable i int64 i64_from_u64_checked(const uint64 source_val, bool should_assert) // not clamping/capping { const bool would_overflow = (source_val > (uint64)std::numeric_limits::max()); - if (should_assert) + if (should_assert) { ASSERT(!would_overflow); - else if (would_overflow) + } + else if (would_overflow) { detail_stypecast::LogEventWarnWrapper("[Internal] Narrowing conversion from 64 bits unsigned integer to 64 bits signed integer will overflow.\n"); + } + return static_cast(source_val); } template int64 i64_from_u64_checked(T, bool) = delete; // disable implicit type conversion for the inpuT source_valrgument diff --git a/src/game/CServer.cpp b/src/game/CServer.cpp index cbbb47a35..5b9bc5bca 100644 --- a/src/game/CServer.cpp +++ b/src/game/CServer.cpp @@ -975,11 +975,16 @@ bool CServer::OnConsoleCmd( CSString & sText, CTextConsole * pSrc ) size_t iThreadCount = ThreadHolder::get().getActiveThreads(); for ( size_t iThreads = 0; iThreads < iThreadCount; ++iThreads ) { - IThread * thrCurrent = ThreadHolder::get().getThreadAt(iThreads); + AbstractThread * thrCurrent = ThreadHolder::get().getThreadAt(iThreads); if (thrCurrent != nullptr) { - pSrc->SysMessagef("%" PRIuSIZE_T " - Id: %" PRIu64 ", Priority: %d, Name: %s.\n", - (iThreads + 1), (uint64)thrCurrent->getId(), thrCurrent->getPriority(), thrCurrent->getName()); + pSrc->SysMessagef( + "%" PRIuSIZE_T " - Id: %" PRIu64 ", Priority: %d, Name: %s.\n", + (iThreads + 1), + (uint64)thrCurrent->getId(), + enum_alias_cast(thrCurrent->getPriority()), + thrCurrent->getName() + ); } } } break; @@ -1362,7 +1367,7 @@ void CServer::ProfileDump( CTextConsole * pSrc, bool bDump ) size_t uiThreadCount = ThreadHolder::get().getActiveThreads(); for ( size_t iThreads = 0; iThreads < uiThreadCount; ++iThreads) { - IThread* thrCurrent = ThreadHolder::get().getThreadAt(iThreads); + AbstractThread* thrCurrent = ThreadHolder::get().getThreadAt(iThreads); if (thrCurrent == nullptr) continue; diff --git a/src/game/CServerConfig.cpp b/src/game/CServerConfig.cpp index b30cdb9f1..28bbb5a4c 100644 --- a/src/game/CServerConfig.cpp +++ b/src/game/CServerConfig.cpp @@ -317,7 +317,7 @@ CServerConfig::CServerConfig() // Networking _uiNetworkThreads = 0; // if there aren't the ini settings, by default we'll not use additional network threads - _uiNetworkThreadPriority= IThread::Disabled; + _iNetworkThreadPriority = enum_alias_cast(ThreadPriority::Disabled); m_fUseAsyncNetwork = 0; m_iNetMaxPings = 15; m_iNetHistoryTTLSeconds = 300; @@ -644,7 +644,7 @@ enum RC_TYPE RC_MYSQLTICKS, // m_fMySqlTicks RC_MYSQLUSER, // m_sMySqlUser RC_NETTTL, // m_iNetHistoryTTL - RC_NETWORKTHREADPRIORITY, // _uiNetworkThreadPriority + RC_NETWORKTHREADPRIORITY, // _iNetworkThreadPriority RC_NETWORKTHREADS, // _uiNetworkThreads RC_NORESROBE, RC_NOTOTIMEOUT, @@ -937,7 +937,7 @@ const CAssocReg CServerConfig::sm_szLoadKeys[RC_QTY + 1] { "MYSQLTICKS", { ELEM_BOOL, static_castOFFSETOF(CServerConfig,m_fMySqlTicks) }}, { "MYSQLUSER", { ELEM_CSTRING, static_castOFFSETOF(CServerConfig,m_sMySqlUser) }}, { "NETTTL", { ELEM_INT, static_castOFFSETOF(CServerConfig, m_iNetHistoryTTLSeconds) }}, - { "NETWORKTHREADPRIORITY", { ELEM_MASK_INT,static_castOFFSETOF(CServerConfig,_uiNetworkThreadPriority)}}, + { "NETWORKTHREADPRIORITY", { ELEM_MASK_INT,static_castOFFSETOF(CServerConfig,_iNetworkThreadPriority)}}, { "NETWORKTHREADS", { ELEM_MASK_INT,static_castOFFSETOF(CServerConfig,_uiNetworkThreads) }}, { "NORESROBE", { ELEM_BOOL, static_castOFFSETOF(CServerConfig,m_fNoResRobe) }}, { "NOTOTIMEOUT", { ELEM_INT, static_castOFFSETOF(CServerConfig,m_iNotoTimeout) }}, @@ -1483,15 +1483,15 @@ bool CServerConfig::r_LoadVal( CScript &s ) case RC_NETWORKTHREADPRIORITY: { - int priority = s.GetArgVal(); - if (priority < 1) - priority = IThread::Normal; - else if (priority > 4) - priority = IThread::RealTime; + int priority = s.GetArgVal(); + if (priority < 1) + priority = enum_alias_cast(ThreadPriority::Normal); + else if (priority > 4) + priority = enum_alias_cast(ThreadPriority::RealTime); else - priority = IThread::Low + (IThread::Priority)priority; + priority = enum_alias_cast(ThreadPriority::Low) + priority; - _uiNetworkThreadPriority = priority; + _iNetworkThreadPriority = priority; } break; case RC_WALKBUFFER: diff --git a/src/game/CServerConfig.h b/src/game/CServerConfig.h index 615bb6e99..f47025fc2 100644 --- a/src/game/CServerConfig.h +++ b/src/game/CServerConfig.h @@ -569,7 +569,7 @@ extern class CServerConfig : public CResourceHolder // network settings uint _uiNetworkThreads; // number of network threads to create - uint _uiNetworkThreadPriority; // priority of network threads + int _iNetworkThreadPriority; // priority of network threads int m_fUseAsyncNetwork; // 0=normal send, 1=async send, 2=async send for 4.0.0+ only int m_iNetMaxPings; // max pings before blocking an ip int m_iNetHistoryTTLSeconds; // time to remember an ip diff --git a/src/game/spheresvr.cpp b/src/game/spheresvr.cpp index 5b989a4de..38b696f56 100644 --- a/src/game/spheresvr.cpp +++ b/src/game/spheresvr.cpp @@ -173,7 +173,7 @@ static PingServer g_PingServer; // Main server loop MainThread::MainThread() - : AbstractSphereThread("T_Main", IThread::RealTime) + : AbstractSphereThread("T_Main", ThreadPriority::RealTime) { m_profile.EnableProfile(PROFILE_NETWORK_RX); m_profile.EnableProfile(PROFILE_CLIENTS); @@ -492,14 +492,14 @@ int _cdecl main( int argc, char * argv[] ) { // Ensure i have this to have context for ADDTOCALLSTACK and other operations. - const IThread* curthread = ThreadHolder::get().current(); + const AbstractThread* curthread = ThreadHolder::get().current(); ASSERT(curthread != nullptr); ASSERT(dynamic_cast(curthread)); (void)curthread; } #ifndef _WIN32 - IThread::setThreadName("T_SphereStartup"); + AbstractThread::setThreadName("T_SphereStartup"); g_UnixTerminal.start(); @@ -531,7 +531,7 @@ int _cdecl main( int argc, char * argv[] ) if (fShouldCoreRunInSeparateThread) { g_Main.start(); // Starts another thread to do all the work (it does Sphere_OnTick()) - IThread::setThreadName("T_Monitor"); + AbstractThread::setThreadName("T_Monitor"); Sphere_MainMonitorLoop(); // Use this thread to monitor if the others are stuck } else diff --git a/src/network/CNetState.cpp b/src/network/CNetState.cpp index 0ca402c38..ae3ecc506 100644 --- a/src/network/CNetState.cpp +++ b/src/network/CNetState.cpp @@ -242,7 +242,7 @@ void CNetState::markReadClosed(void) volatile DEBUGNETWORK(("%x:Client being closed by read-thread\n", m_id)); m_isReadClosed = true; - if (m_parent != nullptr && m_parent->getPriority() == IThread::Disabled) + if (m_parent != nullptr && m_parent->getPriority() == ThreadPriority::Disabled) m_parent->awaken(); } diff --git a/src/network/CNetworkInput.cpp b/src/network/CNetworkInput.cpp index 23380e34d..70f050b37 100644 --- a/src/network/CNetworkInput.cpp +++ b/src/network/CNetworkInput.cpp @@ -54,7 +54,7 @@ bool CNetworkInput::processInput() { // if the thread does not receive ticks, we must perform a quick select to see if we should // wake up the thread - if (m_thread->isActive() && m_thread->getPriority() == IThread::Disabled) + if (m_thread->isActive() && m_thread->getPriority() == ThreadPriority::Disabled) { fd_set fds; if (checkForData(fds)) diff --git a/src/network/CNetworkManager.cpp b/src/network/CNetworkManager.cpp index d38e00fa9..c2ee43980 100644 --- a/src/network/CNetworkManager.cpp +++ b/src/network/CNetworkManager.cpp @@ -391,7 +391,7 @@ void CNetworkManager::start(void) if (ntCount > 1) { // If we have more than one thread (this hasn't sense... at this point isThreaded should be == true) - char name[IThread::m_nameMaxLength]; + char name[AbstractThread::m_nameMaxLength]; snprintf(name, sizeof(name), "T_Net #%u", (uint)pThread->getId()); pThread->overwriteInternalThreadName(name); } @@ -453,7 +453,7 @@ void CNetworkManager::tick(void) // sent from CNetworkOutput::QueuePacketTransaction can be ignored // the safest solution to this is to send additional signals from here CNetworkThread* thread = state->getParentThread(); - if (thread != nullptr && state->hasPendingData() && thread->getPriority() == IThread::Disabled) + if (thread != nullptr && state->hasPendingData() && thread->getPriority() == ThreadPriority::Disabled) thread->awaken(); #endif continue; diff --git a/src/network/CNetworkOutput.cpp b/src/network/CNetworkOutput.cpp index 17c8fb1c5..445c24df1 100644 --- a/src/network/CNetworkOutput.cpp +++ b/src/network/CNetworkOutput.cpp @@ -126,7 +126,7 @@ bool CNetworkOutput::processOutput() if (packetsSent > 0) { // notify thread there could be more to process - if (m_thread->getPriority() == IThread::Disabled) + if (m_thread->getPriority() == ThreadPriority::Disabled) m_thread->awaken(); } @@ -173,7 +173,7 @@ size_t CNetworkOutput::flush(CNetState* state) // when this isn't the active thread, all we can do is raise a request to flush this // client later state->markFlush(true); - if (m_thread->getPriority() == IThread::Disabled) + if (m_thread->getPriority() == ThreadPriority::Disabled) m_thread->awaken(); return 0; @@ -647,6 +647,6 @@ void CNetworkOutput::QueuePacketTransaction(PacketTransaction* transaction) // notify thread CNetworkThread* thread = state->getParentThread(); - if (thread != nullptr && thread->getPriority() == IThread::Disabled) + if (thread != nullptr && thread->getPriority() == ThreadPriority::Disabled) thread->awaken(); } diff --git a/src/network/CNetworkThread.cpp b/src/network/CNetworkThread.cpp index bedb35de3..0ebb6db11 100644 --- a/src/network/CNetworkThread.cpp +++ b/src/network/CNetworkThread.cpp @@ -12,13 +12,13 @@ static const char* GenerateNetworkThreadName(size_t id) { char* name = Str_GetTemp(); - snprintf(name, IThread::m_nameMaxLength, "T_Net #%" PRIuSIZE_T, id); + snprintf(name, AbstractThread::m_nameMaxLength, "T_Net #%" PRIuSIZE_T, id); return name; } CNetworkThread::CNetworkThread(CNetworkManager* manager, size_t id) - : AbstractSphereThread(GenerateNetworkThreadName(id), IThread::Disabled), + : AbstractSphereThread(GenerateNetworkThreadName(id), ThreadPriority::Disabled), m_manager(manager), m_id(id), _iTimeLastStateDataCheck(0) { } @@ -31,7 +31,7 @@ void CNetworkThread::assignNetworkState(CNetState* state) { ADDTOCALLSTACK("CNetworkThread::assignNetworkState"); m_assignQueue.push(state); - if (getPriority() == IThread::Disabled) + if (getPriority() == ThreadPriority::Disabled) awaken(); } @@ -113,8 +113,8 @@ void CNetworkThread::tick(void) if (m_states.empty()) { // we haven't been assigned any clients, so go idle for now - if (getPriority() != IThread::Disabled) - setPriority(IThread::Low); + if (getPriority() != ThreadPriority::Disabled) + setPriority(ThreadPriority::Low); return; } @@ -122,7 +122,7 @@ void CNetworkThread::tick(void) processOutput(); // we're active, take priority - setPriority(static_cast(g_Cfg._uiNetworkThreadPriority)); + setPriority(static_cast(g_Cfg._iNetworkThreadPriority)); static constexpr int64 kiStateDataCheckPeriod = 10 * 1000; // 10 seconds, expressed in milliseconds const int64 iTimeCur = CSTime::GetMonotonicSysTimeMilli(); diff --git a/src/network/PingServer.cpp b/src/network/PingServer.cpp index 0c2c3ec50..2627c1227 100644 --- a/src/network/PingServer.cpp +++ b/src/network/PingServer.cpp @@ -6,7 +6,7 @@ static PingServer s_PingServer; // run the thread in RealTime as we need pings to be responded to ASAP -PingServer::PingServer() : AbstractSphereThread("PingServer", IThread::RealTime) +PingServer::PingServer() : AbstractSphereThread("PingServer", ThreadPriority::RealTime) { m_profile.EnableProfile(PROFILE_NETWORK_RX); m_profile.EnableProfile(PROFILE_NETWORK_TX); diff --git a/src/network/linuxev.cpp b/src/network/linuxev.cpp index 122d748ac..c946fcfe5 100644 --- a/src/network/linuxev.cpp +++ b/src/network/linuxev.cpp @@ -63,7 +63,7 @@ static void socketslave_cb(struct ev_loop *loop, struct ev_io *watcher, int reve static constexpr double kLoopCollectNetworkInputSeconds = 0.002; static constexpr double kLoopWaitBeforeNextCycleSeconds = 0.008; -LinuxEv::LinuxEv(void) : AbstractSphereThread("T_NetLoopOut", IThread::High) +LinuxEv::LinuxEv(void) : AbstractSphereThread("T_NetLoopOut", ThreadPriority::High) //, m_watchMainsock{} { // Right now, we use libev to send asynchronously packets to clients. diff --git a/src/sphere/ProfileTask.cpp b/src/sphere/ProfileTask.cpp index 500a837cf..9ff76d6b0 100644 --- a/src/sphere/ProfileTask.cpp +++ b/src/sphere/ProfileTask.cpp @@ -21,7 +21,7 @@ ProfileTask::ProfileTask(PROFILE_TYPE id) : if (th.closing()) return; - IThread* icontext = th.current(); + AbstractThread* icontext = th.current(); if (icontext == nullptr) { // Thread was deleted, manually or by app closing signal. diff --git a/src/sphere/UnixTerminal.cpp b/src/sphere/UnixTerminal.cpp index e3e961b13..f11449411 100644 --- a/src/sphere/UnixTerminal.cpp +++ b/src/sphere/UnixTerminal.cpp @@ -11,7 +11,7 @@ #endif -UnixTerminal::UnixTerminal() : AbstractSphereThread("T_UnixTerm", IThread::Highest), +UnixTerminal::UnixTerminal() : AbstractSphereThread("T_UnixTerm", ThreadPriority::Highest), #ifdef _USECURSES m_window(nullptr), #else diff --git a/src/sphere/asyncdb.cpp b/src/sphere/asyncdb.cpp index cff073390..d2685c9ad 100644 --- a/src/sphere/asyncdb.cpp +++ b/src/sphere/asyncdb.cpp @@ -6,7 +6,7 @@ CDataBaseAsyncHelper g_asyncHdb; -CDataBaseAsyncHelper::CDataBaseAsyncHelper(void) : AbstractSphereThread("AsyncDatabaseHelper", IThread::Low) +CDataBaseAsyncHelper::CDataBaseAsyncHelper(void) : AbstractSphereThread("AsyncDatabaseHelper", ThreadPriority::Low) { } diff --git a/src/sphere/ntservice.cpp b/src/sphere/ntservice.cpp index a346d593b..0e0bdb707 100644 --- a/src/sphere/ntservice.cpp +++ b/src/sphere/ntservice.cpp @@ -457,7 +457,7 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine #endif { UnreferencedParameter(hPrevInstance); - IThread::setThreadName("T_SphereStartup"); + AbstractThread::setThreadName("T_SphereStartup"); TCHAR *argv[32]; argv[0] = nullptr; diff --git a/src/sphere/ntwindow.cpp b/src/sphere/ntwindow.cpp index c9f8a049d..ce3a38b73 100644 --- a/src/sphere/ntwindow.cpp +++ b/src/sphere/ntwindow.cpp @@ -100,7 +100,7 @@ void CNTWindow::CStatusDlg::FillStats() size_t iThreadCount = ThreadHolder::get().getActiveThreads(); for ( size_t iThreads = 0; iThreads < iThreadCount; ++iThreads) { - IThread* thrCurrent = ThreadHolder::get().getThreadAt(iThreads); + AbstractThread* thrCurrent = ThreadHolder::get().getThreadAt(iThreads); if (thrCurrent == nullptr) continue; @@ -163,7 +163,7 @@ BOOL CNTWindow::CStatusDlg::DefDialogProc( UINT message, WPARAM wParam, LPARAM l return false; } -CNTWindow::CNTWindow() : AbstractSphereThread("T_ConsoleWindow", IThread::Highest), +CNTWindow::CNTWindow() : AbstractSphereThread("T_ConsoleWindow", ThreadPriority::Highest), _NTWInitParams{}, m_zCommands {{}} { _fKeepAliveAtShutdown = true; diff --git a/src/sphere/threads.cpp b/src/sphere/threads.cpp index 204ed2e28..9eb3d26f6 100644 --- a/src/sphere/threads.cpp +++ b/src/sphere/threads.cpp @@ -54,74 +54,6 @@ struct TemporaryStringThreadSafeStateHolder } }; -IThread::IThread() noexcept : - m_threadSystemId(0), m_threadHolderId(-1) - { }; - -// This is needed to prevent weak-vtables warning (puts the vtable in this translation unit instead of every translation unit) -IThread::~IThread() noexcept = default; - -#if defined(_WIN32) && defined(MSVC_COMPILER) -#pragma pack(push, 8) -typedef struct tagTHREADNAME_INFO -{ - DWORD dwType; - LPCSTR szName; - DWORD dwThreadID; - DWORD dwFlags; -} THREADNAME_INFO; -#pragma pack(pop) - -static constexpr DWORD MS_VC_EXCEPTION = 0x406D1388; -#endif - -void IThread::setThreadName(const char* name) -{ - // register the thread name - - // Unix uses prctl to set thread name - // thread name must be 16 bytes, zero-padded if shorter - char name_trimmed[m_nameMaxLength] = { '\0' }; // m_nameMaxLength = 16 - Str_CopyLimitNull(name_trimmed, name, m_nameMaxLength); - -#if defined(_WIN32) - #if defined(MSVC_COMPILER) // TODO: support thread naming when compiling with compilers other than Microsoft's - // Windows uses THREADNAME_INFO structure to set thread name - THREADNAME_INFO info; - info.dwType = 0x1000; - info.szName = name_trimmed; - info.dwThreadID = (DWORD)(-1); - info.dwFlags = 0; - - __try - { - RaiseException(MS_VC_EXCEPTION, 0, sizeof(info) / sizeof(ULONG_PTR), (ULONG_PTR*)&info); - } - __except(EXCEPTION_EXECUTE_HANDLER) - { - } - #endif // MSVC_COMPILER -#elif defined(__APPLE__) // Mac - pthread_setname_np(name_trimmed); -#elif !defined(_BSD) // Linux - prctl(PR_SET_NAME, name_trimmed, 0, 0, 0); -#elif defined(__FreeBSD__) || defined(__OpenBSD__) - pthread_set_name_np(getCurrentThreadId(), name_trimmed); -#elif defined(__NetBSD__) - pthread_setname_np(getCurrentThreadId(), "%s", name_trimmed); -#endif - - auto athr = static_cast(ThreadHolder::get().current()); - ASSERT(athr); - -#ifdef _DEBUG - g_Log.Event(LOGF_CONSOLE_ONLY|LOGM_DEBUG|LOGL_EVENT, - "Setting thread (ThreadHolder ID %d, internal name '%s') system name: '%s'.\n", - athr->m_threadHolderId, athr->getName(), name_trimmed); -#endif - athr->overwriteInternalThreadName(name_trimmed); -} - /** * ThreadHolder @@ -144,18 +76,18 @@ bool ThreadHolder::closing() noexcept return ret; } -IThread* ThreadHolder::current() noexcept +AbstractThread* ThreadHolder::current() noexcept { // Do not use ASSERTs here, would cause recursion. // RETRY_SHARED_LOCK_FOR_TASK is used to try to not make mutex lock fail and, if needed, // handle failure while allowing this function to be noexcept. - IThread* retval = nullptr; + AbstractThread* retval = nullptr; RETRY_SHARED_LOCK_FOR_TASK(m_mutex, lock, retval, - ([this, &lock]() -> IThread* + ([this, &lock]() -> AbstractThread* { - const threadid_t tid = IThread::getCurrentThreadSystemId(); + const threadid_t tid = AbstractThread::getCurrentThreadSystemId(); if (m_spherethreadpairs_systemid_ptr.empty()) [[unlikely]] @@ -166,7 +98,7 @@ IThread* ThreadHolder::current() noexcept return nullptr; } - auto thread = static_cast(DummySphereThread::getInstance()); + auto thread = static_cast(DummySphereThread::getInstance()); if (!thread) [[unlikely]] { @@ -200,7 +132,7 @@ IThread* ThreadHolder::current() noexcept RaiseImmediateAbort(); } - auto thread = static_cast(found->second); + auto thread = static_cast(found->second); ASSERT(thread->m_threadHolderId != -1); SphereThreadData *tdata = &(m_threads[thread->m_threadHolderId]); @@ -236,7 +168,7 @@ IThread* ThreadHolder::current() noexcept return retval; } -void ThreadHolder::push(IThread *thread) noexcept +void ThreadHolder::push(AbstractThread *thread) noexcept { bool fExceptionThrown = false; try @@ -244,8 +176,8 @@ void ThreadHolder::push(IThread *thread) noexcept auto sphere_thread = dynamic_cast(thread); if (!sphere_thread) { - //throw CSError(LOGL_FATAL, 0, "IThread not being an AbstractSphereThread?"); - STDERR_LOG("IThread not being an AbstractSphereThread?"); + //throw CSError(LOGL_FATAL, 0, "AbstractThread not being an AbstractSphereThread?"); + STDERR_LOG("AbstractThread not being an AbstractSphereThread?"); fExceptionThrown = true; } @@ -311,23 +243,7 @@ void ThreadHolder::push(IThread *thread) noexcept #endif } -/* -SphereThreadData* ThreadHolder::findThreadData(IThread* thread) noexcept -{ - // If checking for current thread, use another escamotage to retrieve it... - - // This should always run guarded by a MUTEX! - SimpleThreadLock lock(m_mutex); - for (size_t i = 0; i < m_threadCount; ++i) - { - if (m_threads[i].m_ptr == thread) - return &(m_threads[i]); - } - return nullptr; -} -*/ - -void ThreadHolder::remove(IThread *thread) CANTHROW +void ThreadHolder::remove(AbstractThread *thread) CANTHROW { if (!thread) throw CSError(LOGL_FATAL, 0, "thread == nullptr"); @@ -373,11 +289,11 @@ void ThreadHolder::markThreadsClosing() CANTHROW } } -IThread * ThreadHolder::getThreadAt(size_t at) noexcept +AbstractThread * ThreadHolder::getThreadAt(size_t at) noexcept { - IThread* retval = nullptr; + AbstractThread* retval = nullptr; RETRY_SHARED_LOCK_FOR_TASK(m_mutex, lock, retval, - ([this, at]() -> IThread* + ([this, at]() -> AbstractThread* { // MSVC: warning C5101: use of preprocessor directive in function-like macro argument list is undefined behavior. //#ifdef _DEBUG @@ -389,7 +305,7 @@ IThread * ThreadHolder::getThreadAt(size_t at) noexcept } //#endif - if ( at > getActiveThreads() ) + if ( at > getActiveThreads() ) [[unlikely]] { return nullptr; @@ -418,7 +334,8 @@ IThread * ThreadHolder::getThreadAt(size_t at) noexcept */ int AbstractThread::m_threadsAvailable = 0; -AbstractThread::AbstractThread(const char *name, IThread::Priority priority) : +AbstractThread::AbstractThread(const char *name, ThreadPriority priority) : + m_threadSystemId(0), m_threadHolderId(-1), _fKeepAliveAtShutdown(false), _fIsClosing(false) { if( AbstractThread::m_threadsAvailable == 0 ) @@ -733,7 +650,7 @@ void AbstractThread::onStart() ThreadHolder::get().push(this); - if (isActive()) // This thread has actually been spawned and the code is executing on a different thread + if (isActive()) // This thread has actually been spawned and the code is executing on a different thread setThreadName(getName()); #ifdef _DEBUG @@ -743,36 +660,36 @@ void AbstractThread::onStart() #endif } -void AbstractThread::setPriority(IThread::Priority pri) +void AbstractThread::setPriority(ThreadPriority pri) { - ASSERT(((pri >= IThread::Idle) && (pri <= IThread::RealTime)) || (pri == IThread::Disabled)); + ASSERT(((pri >= ThreadPriority::Idle) && (pri <= ThreadPriority::RealTime)) || (pri == ThreadPriority::Disabled)); m_priority = pri; // detect a sleep period for thread depending on priority switch( m_priority ) { - case IThread::Idle: + case ThreadPriority::Idle: m_tickPeriod = 1000; break; - case IThread::Low: + case ThreadPriority::Low: m_tickPeriod = 200; break; - case IThread::Normal: + case ThreadPriority::Normal: m_tickPeriod = 100; break; - case IThread::High: + case ThreadPriority::High: m_tickPeriod = 50; break; - case IThread::Highest: + case ThreadPriority::Highest: m_tickPeriod = 5; break; - case IThread::RealTime: + case ThreadPriority::RealTime: m_tickPeriod = 0; break; - case IThread::Disabled: + case ThreadPriority::Disabled: m_tickPeriod = AutoResetEvent::_kiInfinite; break; - }\ + } } bool AbstractThread::shouldExit() noexcept @@ -780,10 +697,71 @@ bool AbstractThread::shouldExit() noexcept return closing() || m_terminateRequested || _thread_selfTerminateAfterThisTick; } +void AbstractThread::setThreadName(const char* name) +{ + // register the thread name + + // Unix uses prctl to set thread name + // thread name must be 16 bytes, zero-padded if shorter + char name_trimmed[m_nameMaxLength] = { '\0' }; // m_nameMaxLength = 16 + Str_CopyLimitNull(name_trimmed, name, m_nameMaxLength); + +#if defined(_WIN32) +#if defined(MSVC_COMPILER) + // TODO: support thread naming when compiling with compilers other than Microsoft's + + // Windows uses THREADNAME_INFO structure to set thread name +#pragma pack(push, 8) + typedef struct tagTHREADNAME_INFO + { + DWORD dwType; + LPCSTR szName; + DWORD dwThreadID; + DWORD dwFlags; + } THREADNAME_INFO; +#pragma pack(pop) + static constexpr DWORD MS_VC_EXCEPTION = 0x406D1388; + + THREADNAME_INFO info; + info.dwType = 0x1000; + info.szName = name_trimmed; + info.dwThreadID = (DWORD)(-1); + info.dwFlags = 0; + + __try + { + RaiseException(MS_VC_EXCEPTION, 0, sizeof(info) / sizeof(ULONG_PTR), (ULONG_PTR*)&info); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + } +#endif // MSVC_COMPILER +#elif defined(__APPLE__) // Mac + pthread_setname_np(name_trimmed); +#elif !defined(_BSD) // Linux + prctl(PR_SET_NAME, name_trimmed, 0, 0, 0); +#elif defined(__FreeBSD__) || defined(__OpenBSD__) + pthread_set_name_np(getCurrentThreadId(), name_trimmed); +#elif defined(__NetBSD__) + pthread_setname_np(getCurrentThreadId(), "%s", name_trimmed); +#endif + + auto athr = static_cast(ThreadHolder::get().current()); + ASSERT(athr); + +#ifdef _DEBUG + g_Log.Event(LOGF_CONSOLE_ONLY|LOGM_DEBUG|LOGL_EVENT, + "Setting thread (ThreadHolder ID %d, internal name '%s') system name: '%s'.\n", + athr->m_threadHolderId, athr->getName(), name_trimmed); +#endif + athr->overwriteInternalThreadName(name_trimmed); +} + + /* * AbstractSphereThread */ -AbstractSphereThread::AbstractSphereThread(const char *name, Priority priority) +AbstractSphereThread::AbstractSphereThread(const char *name, ThreadPriority priority) : AbstractThread(name, priority) { #ifdef THREAD_TRACK_CALLSTACK @@ -804,7 +782,6 @@ AbstractSphereThread::~AbstractSphereThread() _fIsClosing = true; } - char *AbstractSphereThread::allocateBuffer() noexcept { auto* tsholder = TemporaryStringThreadSafeStateHolder::get(); @@ -976,7 +953,7 @@ void AbstractSphereThread::printStackTrace() noexcept DummySphereThread *DummySphereThread::_instance = nullptr; DummySphereThread::DummySphereThread() - : AbstractSphereThread("dummy", IThread::Normal) + : AbstractSphereThread("dummy", ThreadPriority::Normal) { } @@ -1016,7 +993,7 @@ StackDebugInformation::StackDebugInformation(const char *name) noexcept if (th.closing()) [[unlikely]] return; - IThread *icontext = th.current(); + AbstractThread *icontext = th.current(); if (icontext == nullptr) [[unlikely]] { @@ -1048,14 +1025,14 @@ StackDebugInformation::~StackDebugInformation() noexcept void StackDebugInformation::printStackTrace() noexcept // static { - IThread* pThreadState = ThreadHolder::get().current(); + AbstractThread* pThreadState = ThreadHolder::get().current(); if (pThreadState) static_cast(pThreadState)->printStackTrace(); } void StackDebugInformation::freezeCallStack(bool freeze) noexcept // static { - IThread* pThreadState = ThreadHolder::get().current(); + AbstractThread* pThreadState = ThreadHolder::get().current(); if (pThreadState) static_cast(pThreadState)->freezeCallStack(freeze); } diff --git a/src/sphere/threads.h b/src/sphere/threads.h index 1a2fb0598..2b72d6c4b 100644 --- a/src/sphere/threads.h +++ b/src/sphere/threads.h @@ -44,10 +44,10 @@ #define SPHERE_THREADENTRY_CALLTYPE #endif -class IThread; +class AbstractThread; // stores a value unique to each thread, intended to hold -// a pointer (e.g. the current IThread instance) +// a pointer (e.g. the current AbstractThread instance) template class TlsValue { @@ -131,92 +131,36 @@ T TlsValue::get() const #endif } +enum class ThreadPriority : int +{ + Idle, // tick 1000ms + Low, // tick 200ms + Normal, // tick 100ms + High, // tick 50ms + Highest, // tick 5ms + RealTime, // tick almost instantly + Disabled = 0xFF // tick never +}; -// Interface for threads. Almost always should be used instead of any implementing classes -class IThread +// Thread base implementation, without Sphere "extensions". +class AbstractThread { -public: // TODO: lazy - threadid_t m_threadSystemId; - int m_threadHolderId; + friend class ThreadHolder; + static int m_threadsAvailable; public: - enum Priority - { - Idle, // tick 1000ms - Low, // tick 200ms - Normal, // tick 100ms - High, // tick 50ms - Highest, // tick 5ms - RealTime, // tick almost instantly - Disabled = 0xFF // tick never - }; - - IThread() noexcept; - virtual ~IThread() noexcept; - - virtual threadid_t getId() const = 0; - virtual const char *getName() const = 0; - - virtual bool isActive() const = 0; - virtual bool checkStuck() = 0; - - virtual void start() = 0; - virtual void terminate(bool ended) = 0; - virtual void waitForClose() = 0; - - virtual void setPriority(Priority) = 0; - virtual Priority getPriority() const = 0; - - static inline threadid_t getCurrentThreadSystemId() noexcept - { -#if defined(_WIN32) - return ::GetCurrentThreadId(); -#elif defined(__APPLE__) - // On OSX, 'threadid_t' is not an integer but a '_opaque_pthread_t *'), so we need to resort to another method. - uint64_t threadid = 0; - pthread_threadid_np(pthread_self(), &threadid); - return threadid; -#else - return pthread_self(); -#endif - } - static inline bool isSameThreadId(threadid_t firstId, threadid_t secondId) noexcept - { -#if defined(_WIN32) || defined(__APPLE__) - return (firstId == secondId); -#else - return pthread_equal(firstId,secondId); -#endif - } - - inline bool isSameThread(threadid_t otherThreadId) const noexcept - { - return isSameThreadId(getCurrentThreadSystemId(), otherThreadId); - } - - static constexpr uint m_nameMaxLength = 16; // Unix support a max 16 bytes thread name. - static void setThreadName(const char* name); + static constexpr uint m_nameMaxLength = 16; // Unix support a max 16 bytes thread name. protected: - virtual bool shouldExit() noexcept = 0; -}; - - -// Thread implementation. See IThread for list of available methods. -class AbstractThread : public IThread -{ - friend class ThreadHolder; + threadid_t m_threadSystemId; + int m_threadHolderId; -protected: bool _fKeepAliveAtShutdown; volatile std::atomic_bool _thread_selfTerminateAfterThisTick; volatile std::atomic_bool _fIsClosing; - private: volatile std::atomic_bool m_terminateRequested; - char m_name[30]; - static int m_threadsAvailable; // pthread_t type is opaque (platform-defined). It can be an integer, a struct, a ptr something. Memset is the safest and more portable way. //spherethread_t m_handle; @@ -224,50 +168,81 @@ class AbstractThread : public IThread std::optional m_handle; uint m_hangCheck; - Priority m_priority; + ThreadPriority m_priority; uint m_tickPeriod; AutoResetEvent m_sleepEvent; ManualResetEvent m_terminateEvent; public: - AbstractThread(const char *name, Priority priority = IThread::Normal); + AbstractThread(const char *name, ThreadPriority priority = ThreadPriority::Normal); virtual ~AbstractThread(); AbstractThread(const AbstractThread& copy) = delete; AbstractThread& operator=(const AbstractThread& other) = delete; public: - virtual threadid_t getId() const noexcept override { return m_threadSystemId; } - virtual const char *getName() const noexcept override { return m_name; } + threadid_t getId() const noexcept { return m_threadSystemId; } + virtual const char *getName() const noexcept { return m_name; } - virtual bool isActive() const override; - virtual bool checkStuck() override; + virtual bool isActive() const; + virtual bool checkStuck(); - virtual void start() override; - virtual void terminate(bool ended) override; - virtual void waitForClose() override; + virtual void start(); + virtual void terminate(bool ended); + virtual void waitForClose(); void awaken(); - virtual void setPriority(Priority pri) override; - virtual Priority getPriority() const override { return m_priority; } + void setPriority(ThreadPriority pri); + ThreadPriority getPriority() const { return m_priority; } void overwriteInternalThreadName(const char* name) noexcept; bool isCurrentThread() const noexcept; + protected: + virtual void tick() = 0; + + // NOTE: this should not be too long-lasted function, so no world loading, etc here!!! + virtual void onStart(); + virtual bool shouldExit() noexcept; + + private: + void run(); + static SPHERE_THREADENTRY_RETNTYPE SPHERE_THREADENTRY_CALLTYPE runner(void *callerThread); + + public: + static void setThreadName(const char* name); + bool closing() noexcept { return _fIsClosing; } -protected: - virtual void tick() = 0; - // NOTE: this should not be too long-lasted function, so no world loading, etc here!!! - virtual void onStart(); - virtual bool shouldExit() noexcept override; + static inline threadid_t getCurrentThreadSystemId() noexcept + { +#if defined(_WIN32) + return ::GetCurrentThreadId(); +#elif defined(__APPLE__) + // On OSX, 'threadid_t' is not an integer but a '_opaque_pthread_t *'), so we need to resort to another method. + uint64_t threadid = 0; + pthread_threadid_np(pthread_self(), &threadid); + return threadid; +#else + return pthread_self(); +#endif + } + static inline bool isSameThreadId(threadid_t firstId, threadid_t secondId) noexcept + { +#if defined(_WIN32) || defined(__APPLE__) + return (firstId == secondId); +#else + return pthread_equal(firstId,secondId); +#endif + } - private: - void run(); - static SPHERE_THREADENTRY_RETNTYPE SPHERE_THREADENTRY_CALLTYPE runner(void *callerThread); + inline bool isSameThread(threadid_t otherThreadId) const noexcept + { + return isSameThreadId(getCurrentThreadSystemId(), otherThreadId); + } }; @@ -289,7 +264,7 @@ class AbstractSphereThread : public AbstractThread #endif public: - AbstractSphereThread(const char *name, Priority priority = IThread::Normal); + AbstractSphereThread(const char *name, ThreadPriority priority = ThreadPriority::Normal); virtual ~AbstractSphereThread(); AbstractSphereThread(const AbstractSphereThread& copy) = delete; @@ -344,8 +319,9 @@ class ThreadHolder { friend class AbstractThread; - struct SphereThreadData { - IThread *m_ptr; + struct SphereThreadData + { + AbstractThread *m_ptr; bool m_closed; }; using spherethreadlist_t = std::vector; @@ -365,7 +341,7 @@ class ThreadHolder friend void Sphere_ExitServer(void); void markThreadsClosing() CANTHROW; - //SphereThreadData* findThreadData(IThread* thread) noexcept; + //SphereThreadData* findThreadData(AbstractThread* thread) noexcept; public: static constexpr lpctstr m_sClassName = "ThreadHolder"; @@ -373,14 +349,14 @@ class ThreadHolder static ThreadHolder& get() noexcept; bool closing() noexcept; - // returns current working thread or DummySphereThread * if no IThread threads are running - IThread *current() noexcept; + // returns current working thread or DummySphereThread * if no AbstractThread threads are running + AbstractThread *current() noexcept; // records a thread to the list. Sould NOT be called, internal usage - void push(IThread *thread) noexcept; + void push(AbstractThread *thread) noexcept; // removes a thread from the list. Sould NOT be called, internal usage - void remove(IThread *thread) CANTHROW; + void remove(AbstractThread *thread) CANTHROW; // returns thread at i pos - IThread * getThreadAt(size_t at) noexcept; + AbstractThread * getThreadAt(size_t at) noexcept; // returns number of running threads. Sould NOT be called, unit tests usage inline size_t getActiveThreads() noexcept { return m_threadCount; } From f28983e4b234e8240dc315f06088332970822dd9 Mon Sep 17 00:00:00 2001 From: cbnolok Date: Thu, 3 Oct 2024 17:11:30 +0200 Subject: [PATCH 19/32] Updated .clang-format/tidy. --- .clang-format | 2 +- .clang-tidy | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.clang-format b/.clang-format index 1cc6ca616..b85f0ee08 100644 --- a/.clang-format +++ b/.clang-format @@ -76,7 +76,7 @@ PackConstructorInitializers: NextLineOnly PenaltyReturnTypeOnItsOwnLine: 200 # Prefer keeping return type on the same line if possible # Indentation settings -#AccessModifierOffset: -4 +AccessModifierOffset: -4 IndentAccessModifiers: false IndentCaseBlocks: false IndentCaseLabels: true diff --git a/.clang-tidy b/.clang-tidy index d051527da..cfd245271 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -57,6 +57,8 @@ Checks: > CheckOptions: - key: 'clang-analyzer-core.NonNullParamChecker:assert_like_macro' value: 'DEBUG_ASSERT,ASSERT,PERSISTANT_ASSERT' + - key: 'clang-analyzer-config:noreturn_function' + value: 'RaiseImmediateAbort,RaiseRecoverableAbort' - { key: readability-identifier-naming.NamespaceCase, value: lower_case } - { key: readability-identifier-naming.ClassCase, value: CamelCase } - { key: readability-identifier-naming.StructCase, value: CamelCase } From 03ce5f6cc30df81d3a652d640a04efd31bad5f25 Mon Sep 17 00:00:00 2001 From: cbnolok Date: Fri, 4 Oct 2024 17:09:51 +0200 Subject: [PATCH 20/32] Added CSString::SetValFalse/True to have a unified way of setting 0 or 1 as a return value. Fixed regression for FOLLOWERSLOTS. --- cmake/CompilerFlagsChecker.cmake | 2 +- src/common/CDataBase.cpp | 2 +- src/common/CScriptObj.cpp | 8 ++++---- src/common/CScriptTriggerArgs.cpp | 2 +- src/common/ListDefContMap.cpp | 2 +- src/common/sphere_library/CSString.cpp | 18 +++++++++++++---- src/common/sphere_library/CSString.h | 10 +++++++++ src/game/CObjBase.cpp | 6 +++--- src/game/CServerConfig.cpp | 14 ++++++------- src/game/chars/CChar.cpp | 28 ++++++++++++++++---------- src/game/chars/CCharNPC.cpp | 4 ++-- src/game/chars/CCharPlayer.cpp | 4 ++-- src/game/clients/CClientEvent.cpp | 12 +++++------ src/game/clients/CParty.cpp | 4 ++-- src/game/components/CCChampion.cpp | 2 +- src/game/components/CCMultiMovable.cpp | 2 +- src/game/components/CCSpawn.cpp | 2 +- src/game/items/CItem.cpp | 2 +- src/game/items/CItemBase.cpp | 2 +- src/game/items/CItemMulti.cpp | 2 +- src/game/items/CItemShip.cpp | 4 ++-- src/game/items/CItemStone.cpp | 8 ++++---- 22 files changed, 83 insertions(+), 57 deletions(-) diff --git a/cmake/CompilerFlagsChecker.cmake b/cmake/CompilerFlagsChecker.cmake index 7bfb40fe0..b0e183dc0 100644 --- a/cmake/CompilerFlagsChecker.cmake +++ b/cmake/CompilerFlagsChecker.cmake @@ -18,7 +18,7 @@ if(NOT MSVC) # Linker flags (warnings) #check_cxx_compiler_flag("-Wl,--fatal-warnings" COMP_LINKER_HAS_FATAL_WARNINGS_V1) - #check_cxx_compiler_flag("-Wl,-fatal-warnings" COMP_LINKER_HAS_FATAL_WARNINGS_V2) + #check_cxx_compiler_flag("-Wl,-fatal_warnings" COMP_LINKER_HAS_FATAL_WARNINGS_V2) if(CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang") set(COMP_LINKER_HAS_FATAL_WARNINGS_V2 TRUE) else() diff --git a/src/common/CDataBase.cpp b/src/common/CDataBase.cpp index 4f56d3a34..909ee56c8 100644 --- a/src/common/CDataBase.cpp +++ b/src/common/CDataBase.cpp @@ -403,7 +403,7 @@ bool CDataBase::r_WriteVal(lpctstr ptcKey, CSString &sVal, CTextConsole *pSrc, b { ptcKey += strlen(sm_szLoadKeys[index]); GETNONWHITESPACE(ptcKey); - sVal.FormatVal(0); + sVal.SetValFalse(); if ( ptcKey[0] != '\0' ) { diff --git a/src/common/CScriptObj.cpp b/src/common/CScriptObj.cpp index 684109e4d..73c5d2575 100644 --- a/src/common/CScriptObj.cpp +++ b/src/common/CScriptObj.cpp @@ -496,7 +496,7 @@ bool CScriptObj::r_WriteVal( lpctstr ptcKey, CSString &sVal, CTextConsole * pSrc if (pRef == nullptr) { // Invalid ref: just return 0, it isn't an error. - sVal.FormatVal(0); + sVal.SetValFalse(); return true; } @@ -516,7 +516,7 @@ bool CScriptObj::r_WriteVal( lpctstr ptcKey, CSString &sVal, CTextConsole * pSrc if (pRef == nullptr) // good command but bad reference. { - sVal.FormatVal(0); + sVal.SetValFalse(); return false; } return pRef->r_WriteVal( ptcKey, sVal, pSrc ); @@ -667,7 +667,7 @@ bool CScriptObj::r_WriteVal( lpctstr ptcKey, CSString &sVal, CTextConsole * pSrc if ( pVar ) sVal = pVar->GetValStr(); else if ( fZero ) - sVal = "0"; + sVal.SetValFalse(); } return true; case SSC_RESDEF0: @@ -679,7 +679,7 @@ bool CScriptObj::r_WriteVal( lpctstr ptcKey, CSString &sVal, CTextConsole * pSrc if ( pVar ) sVal = pVar->GetValStr(); else if ( fZero ) - sVal = "0"; + sVal.SetValFalse(); } return true; case SSC_DEFMSG: diff --git a/src/common/CScriptTriggerArgs.cpp b/src/common/CScriptTriggerArgs.cpp index 698e1269b..f967d1d32 100644 --- a/src/common/CScriptTriggerArgs.cpp +++ b/src/common/CScriptTriggerArgs.cpp @@ -543,7 +543,7 @@ bool CScriptTriggerArgs::r_WriteVal( lpctstr ptcKey, CSString &sVal, CTextConsol if ( pObj ) sVal.FormatHex(pObj->GetUID()); else - sVal.FormatVal(0); + sVal.SetValFalse(); } break; case AGC_S: diff --git a/src/common/ListDefContMap.cpp b/src/common/ListDefContMap.cpp index d66757261..7d092eafb 100644 --- a/src/common/ListDefContMap.cpp +++ b/src/common/ListDefContMap.cpp @@ -268,7 +268,7 @@ bool CListDefCont::AddElementStr(lpctstr ptcKey) if ( (m_listElements.size() + 1) >= INTPTR_MAX ) // overflow? is it even useful? return false; - REMOVE_QUOTES( ptcKey ); + REMOVE_QUOTES( ptcKey ); m_listElements.emplace_back( new CListDefContStr(m_Key.GetBuffer(), ptcKey) ); diff --git a/src/common/sphere_library/CSString.cpp b/src/common/sphere_library/CSString.cpp index 8ae01f185..fdd3db4c9 100644 --- a/src/common/sphere_library/CSString.cpp +++ b/src/common/sphere_library/CSString.cpp @@ -103,9 +103,9 @@ bool CSString::IsValid() const noexcept int CSString::Resize(int iNewLength, bool fPreciseSize) { - if (iNewLength >= m_iMaxLength) + const bool fValid = IsValid(); + if ((iNewLength >= m_iMaxLength) || !fValid) { - const bool fValid = IsValid(); #ifdef DEBUG_STRINGS gMemAmount -= m_iMaxLength; #endif @@ -131,9 +131,9 @@ int CSString::Resize(int iNewLength, bool fPreciseSize) { const int iMinLength = 1 + minimum(iNewLength, m_iLength); Str_CopyLimitNull(pNewData, m_pchData, iMinLength); - delete[] m_pchData; } - pNewData[m_iLength] = '\0'; + if (fValid) + delete[] m_pchData; m_pchData = pNewData; } ASSERT(m_pchData); @@ -142,6 +142,16 @@ int CSString::Resize(int iNewLength, bool fPreciseSize) return m_iLength; } +void CSString::SetValFalse() +{ + Copy("0"); +} + +void CSString::SetValTrue() +{ + Copy("1"); +} + // CSString:: Element access diff --git a/src/common/sphere_library/CSString.h b/src/common/sphere_library/CSString.h index 5537b4015..ce0949e0a 100644 --- a/src/common/sphere_library/CSString.h +++ b/src/common/sphere_library/CSString.h @@ -214,6 +214,16 @@ class CSString */ void SetAt(int nIndex, tchar ch); + /** + * @brief Sets the string to an integer false value (0), usually handy for scripts return values. + */ + void SetValFalse(); + + /** + * @brief Sets the string to an integer true value (1), usually handy for scripts return values. + */ + void SetValTrue(); + ///@} /** @name Modifiers: diff --git a/src/game/CObjBase.cpp b/src/game/CObjBase.cpp index fdec42ab5..cecbdb93a 100644 --- a/src/game/CObjBase.cpp +++ b/src/game/CObjBase.cpp @@ -1132,10 +1132,10 @@ bool CObjBase::r_WriteVal( lpctstr ptcKey, CSString &sVal, CTextConsole * pSrc, if ( pChar ) sVal.FormatVal(bCanSee ? pChar->CanSee(pObj) : pChar->CanSeeLOS(pt, nullptr, pChar->GetVisualRange(), flags)); else - sVal.FormatVal(0); + sVal.SetValFalse(); } else if ( !pChar ) // no char -> no see - sVal.FormatVal(0); + sVal.SetValFalse(); else // standart way src TO current object sVal.FormatVal(bCanSee ? pChar->CanSee(this) : pChar->CanSeeLOS(this, (word)(flags))); } @@ -1199,7 +1199,7 @@ bool CObjBase::r_WriteVal( lpctstr ptcKey, CSString &sVal, CTextConsole * pSrc, GETNONWHITESPACE( ptcKey ); CClient * pThisClient = pSrc->GetChar() ? ( pSrc->GetChar()->IsClientActive() ? pSrc->GetChar()->GetClientActive() : nullptr ) : nullptr; - sVal.FormatVal(0); + sVal.SetValFalse(); if ( pThisClient ) { diff --git a/src/game/CServerConfig.cpp b/src/game/CServerConfig.cpp index 28bbb5a4c..2cf770e64 100644 --- a/src/game/CServerConfig.cpp +++ b/src/game/CServerConfig.cpp @@ -1632,7 +1632,7 @@ bool CServerConfig::r_WriteVal( lpctstr ptcKey, CSString & sVal, CTextConsole * if ( !strnicmp(ptcKey, "MAP(", 4) ) { ptcKey += 4; - sVal.FormatVal(0); + sVal.SetValFalse(); // Parse the arguments after the round brackets tchar * pszArgsNext; @@ -1691,7 +1691,7 @@ bool CServerConfig::r_WriteVal( lpctstr ptcKey, CSString & sVal, CTextConsole * lpctstr pszCmd = ptcKey + 8; int iNumber = Exp_GetVal(pszCmd); SKIP_SEPARATORS(pszCmd); - sVal.FormatVal(0); + sVal.SetValFalse(); if (!*pszCmd) { @@ -1738,7 +1738,7 @@ bool CServerConfig::r_WriteVal( lpctstr ptcKey, CSString & sVal, CTextConsole * ptcKey = ptcKey + 3; int iMapNumber = Exp_GetVal(ptcKey); SKIP_SEPARATORS(ptcKey); - sVal.FormatVal(0); + sVal.SetValFalse(); if ( g_MapList.IsMapSupported(iMapNumber) ) { @@ -1784,7 +1784,7 @@ bool CServerConfig::r_WriteVal( lpctstr ptcKey, CSString & sVal, CTextConsole * size_t iNumber = Exp_GetVal(pszCmd); SKIP_SEPARATORS(pszCmd); - sVal.FormatVal(0); + sVal.SetValFalse(); for (size_t i = 0; i < g_World.m_Multis.size(); ++i) { @@ -1832,7 +1832,7 @@ bool CServerConfig::r_WriteVal( lpctstr ptcKey, CSString & sVal, CTextConsole * int iNumber = Exp_GetVal(pszCmd); SKIP_SEPARATORS(pszCmd); - sVal.FormatVal(0); + sVal.SetValFalse(); if (iNumber < 0 || iNumber >= (int) m_Functions.size()) //invalid index can potentially crash the server, this check is strongly needed { @@ -1879,7 +1879,7 @@ bool CServerConfig::r_WriteVal( lpctstr ptcKey, CSString & sVal, CTextConsole * size_t iNumber = Exp_GetVal(pszCmd); SKIP_SEPARATORS(pszCmd); - sVal.FormatVal(0); + sVal.SetValFalse(); for ( size_t i = 0; i < g_World.m_Stones.size(); ++i ) { @@ -1914,7 +1914,7 @@ bool CServerConfig::r_WriteVal( lpctstr ptcKey, CSString & sVal, CTextConsole * if (cli_num >= g_Serv.StatGet( SERV_STAT_CLIENTS )) return false; - sVal.FormatVal(0); + sVal.SetValFalse(); ClientIterator it; for (CClient* pClient = it.next(); pClient != nullptr; pClient = it.next()) { diff --git a/src/game/chars/CChar.cpp b/src/game/chars/CChar.cpp index 37058219e..4a327c08a 100644 --- a/src/game/chars/CChar.cpp +++ b/src/game/chars/CChar.cpp @@ -2360,7 +2360,7 @@ bool CChar::r_WriteVal( lpctstr ptcKey, CSString & sVal, CTextConsole * pSrc, bo return true; } - sVal.FormatVal(0); + sVal.SetValFalse(); ptcKey += 11; if (*ptcKey != '.') return false; @@ -2373,7 +2373,7 @@ bool CChar::r_WriteVal( lpctstr ptcKey, CSString & sVal, CTextConsole * pSrc, bo } // Access objects by ID. - if (*ptcKey != '.' || m_followers.empty()) + if (m_followers.empty()) return false; const uint uiIndex = Exp_GetUVal(ptcKey); @@ -2384,6 +2384,12 @@ bool CChar::r_WriteVal( lpctstr ptcKey, CSString & sVal, CTextConsole * pSrc, bo if (!pCharArg) return false; + if (*ptcKey == '\0') + { + sVal.SetValTrue(); + return true; + } + if (pCharArg->r_WriteVal(ptcKey, sVal, pSrc, fNoCallParent, fNoCallChildren)) return true; @@ -2403,7 +2409,7 @@ bool CChar::r_WriteVal( lpctstr ptcKey, CSString & sVal, CTextConsole * pSrc, bo return true; } - sVal.FormatVal(0); + sVal.SetValFalse(); ptcKey += 8; if ( *ptcKey == '.' ) @@ -2525,7 +2531,7 @@ bool CChar::r_WriteVal( lpctstr ptcKey, CSString & sVal, CTextConsole * pSrc, bo return true; } - sVal.FormatVal(0); + sVal.SetValFalse(); ptcKey += 8; if ( *ptcKey == '.' ) @@ -2630,7 +2636,7 @@ bool CChar::r_WriteVal( lpctstr ptcKey, CSString & sVal, CTextConsole * pSrc, bo --i; } - sVal = "0"; + sVal.SetValFalse(); delete[] pszFameAt0; return true; } @@ -2726,7 +2732,7 @@ bool CChar::r_WriteVal( lpctstr ptcKey, CSString & sVal, CTextConsole * pSrc, bo --i; } - sVal = "0"; + sVal.SetValFalse(); delete[] pszKarmaAt0; return true; } @@ -2812,12 +2818,12 @@ bool CChar::r_WriteVal( lpctstr ptcKey, CSString & sVal, CTextConsole * pSrc, bo CResourceQtyArray Resources; if ( Resources.Load(ptcKey) > 0 && SkillResourceTest( &Resources ) ) { - sVal.FormatVal(1); + sVal.SetValTrue(); return true; } } } - sVal.FormatVal(0); + sVal.SetValFalse(); return true; case CHC_CANMOVE: { @@ -2840,7 +2846,7 @@ bool CChar::r_WriteVal( lpctstr ptcKey, CSString & sVal, CTextConsole * pSrc, bo if ( pItem ) sVal.FormatHex(pItem->m_itFigurine.m_UID); else - sVal.FormatVal(0); + sVal.SetValFalse(); return true; } case CHC_MOVE: @@ -2886,7 +2892,7 @@ bool CChar::r_WriteVal( lpctstr ptcKey, CSString & sVal, CTextConsole * pSrc, bo if ( m_pPlayer != nullptr ) sVal = ( m_pParty != nullptr ) ? "1" : "0"; else - sVal = "0"; + sVal.SetValFalse(); return true; case CHC_ISMYPET: if (!m_pNPC) @@ -2904,7 +2910,7 @@ bool CChar::r_WriteVal( lpctstr ptcKey, CSString & sVal, CTextConsole * pSrc, bo sVal = IsDisconnected() ? "0" : "1"; return true; } - sVal = "0"; + sVal.SetValFalse(); return true; case CHC_ISSTUCK: { diff --git a/src/game/chars/CCharNPC.cpp b/src/game/chars/CCharNPC.cpp index d6cb5a6ac..8f855ef37 100644 --- a/src/game/chars/CCharNPC.cpp +++ b/src/game/chars/CCharNPC.cpp @@ -206,12 +206,12 @@ bool CCharNPC::r_WriteVal( CChar * pChar, lpctstr ptcKey, CSString & sVal ) default: if ( FindTableHeadSorted( ptcKey, CCharPlayer::sm_szLoadKeys, CPC_QTY ) >= 0 ) { - sVal = "0"; + sVal.SetValFalse(); return true; } if ( FindTableSorted( ptcKey, CClient::sm_szLoadKeys, CC_QTY ) >= 0 ) { - sVal = "0"; + sVal.SetValFalse(); return true; } return(false ); diff --git a/src/game/chars/CCharPlayer.cpp b/src/game/chars/CCharPlayer.cpp index dad515de2..5fa0e5ba6 100644 --- a/src/game/chars/CCharPlayer.cpp +++ b/src/game/chars/CCharPlayer.cpp @@ -198,7 +198,7 @@ bool CCharPlayer::r_WriteVal( CChar * pChar, lpctstr ptcKey, CSString & sVal ) if ( pMyGuild ) sVal.FormatHex((dword)pMyGuild->GetUID()); else - sVal.FormatVal(0); + sVal.SetValFalse(); return true; } else if ( *ptcKey == '.' ) @@ -335,7 +335,7 @@ bool CCharPlayer::r_WriteVal( CChar * pChar, lpctstr ptcKey, CSString & sVal ) default: if ( FindTableSorted( ptcKey, CCharNPC::sm_szLoadKeys, CNC_QTY ) >= 0 ) { - sVal = "0"; + sVal.SetValFalse(); return true; } return false; diff --git a/src/game/clients/CClientEvent.cpp b/src/game/clients/CClientEvent.cpp index 5764f0635..84177d14d 100644 --- a/src/game/clients/CClientEvent.cpp +++ b/src/game/clients/CClientEvent.cpp @@ -2236,7 +2236,7 @@ bool CDialogResponseArgs::r_WriteVal( lpctstr ptcKey, CSString &sVal, CTextConso ptcKey += 6; SKIP_SEPARATORS(ptcKey); - size_t iQty = m_CheckArray.size(); + const size_t iQty = m_CheckArray.size(); if ( ptcKey[0] == '\0' ) { sVal.FormatSTVal(iQty); @@ -2254,17 +2254,17 @@ bool CDialogResponseArgs::r_WriteVal( lpctstr ptcKey, CSString &sVal, CTextConso return true; } - dword dwNum = Exp_GetDWSingle( ptcKey ); + const dword dwNum = Exp_GetDWSingle( ptcKey ); SKIP_SEPARATORS(ptcKey); for ( uint i = 0; i < iQty; ++i ) { if ( dwNum == m_CheckArray[i] ) { - sVal = "1"; + sVal.SetValTrue(); return true; } } - sVal = "0"; + sVal.SetValFalse(); return true; } if ( ! strnicmp( ptcKey, "ARGTXT", 6 )) @@ -2272,14 +2272,14 @@ bool CDialogResponseArgs::r_WriteVal( lpctstr ptcKey, CSString &sVal, CTextConso ptcKey += 6; SKIP_SEPARATORS(ptcKey); - size_t iQty = m_TextArray.size(); + const size_t iQty = m_TextArray.size(); if ( ptcKey[0] == '\0' ) { sVal.FormatSTVal(iQty); return true; } - dword dwNum = Exp_GetDWSingle( ptcKey ); + const dword dwNum = Exp_GetDWSingle( ptcKey ); SKIP_SEPARATORS(ptcKey); for ( uint i = 0; i < iQty; ++i ) diff --git a/src/game/clients/CParty.cpp b/src/game/clients/CParty.cpp index 0a4dfdf91..047eeece0 100644 --- a/src/game/clients/CParty.cpp +++ b/src/game/clients/CParty.cpp @@ -614,7 +614,7 @@ bool CPartyDef::r_WriteVal( lpctstr ptcKey, CSString &sVal, CTextConsole *pSrc, { if ( pRef == nullptr ) // good command but bad link. { - sVal = "0"; + sVal.SetValFalse(); return true; } if ( ptcKey[0] == '\0' ) // we where just testing the ref. @@ -623,7 +623,7 @@ bool CPartyDef::r_WriteVal( lpctstr ptcKey, CSString &sVal, CTextConsole *pSrc, if ( pObj ) sVal.FormatHex((dword)pObj->GetUID()); else - sVal.FormatVal(1); + sVal.SetValTrue(); return true; } return pRef->r_WriteVal(ptcKey, sVal, pSrc); diff --git a/src/game/components/CCChampion.cpp b/src/game/components/CCChampion.cpp index b3b7cf164..98266c28a 100644 --- a/src/game/components/CCChampion.cpp +++ b/src/game/components/CCChampion.cpp @@ -959,7 +959,7 @@ bool CCChampion::r_WriteVal(lpctstr ptcKey, CSString& sVal, CTextConsole* pSrc) } else { - sVal.FormatVal(0); + sVal.SetValFalse(); } break; } diff --git a/src/game/components/CCMultiMovable.cpp b/src/game/components/CCMultiMovable.cpp index 53666a36b..95c8efc01 100644 --- a/src/game/components/CCMultiMovable.cpp +++ b/src/game/components/CCMultiMovable.cpp @@ -1317,7 +1317,7 @@ bool CCMultiMovable::r_WriteVal(lpctstr ptcKey, CSString & sVal, CTextConsole * if (pItemThis->m_itShip.m_Pilot.IsValidUID()) sVal.FormatHex(pItemThis->m_itShip.m_Pilot); else - sVal.FormatVal(0); + sVal.SetValFalse(); } break; diff --git a/src/game/components/CCSpawn.cpp b/src/game/components/CCSpawn.cpp index 746397e29..12ddc0cda 100644 --- a/src/game/components/CCSpawn.cpp +++ b/src/game/components/CCSpawn.cpp @@ -865,7 +865,7 @@ bool CCSpawn::r_WriteVal(lpctstr ptcKey, CSString & sVal, CTextConsole *pSrc) } else { - sVal.FormatVal(0); + sVal.SetValFalse(); } return true; } diff --git a/src/game/items/CItem.cpp b/src/game/items/CItem.cpp index e4696be88..4c1277f08 100644 --- a/src/game/items/CItem.cpp +++ b/src/game/items/CItem.cpp @@ -2805,7 +2805,7 @@ bool CItem::r_WriteVal( lpctstr ptcKey, CSString & sVal, CTextConsole * pSrc, bo if ( id != GetDispID() ) sVal.FormatHex( id ); else - sVal.FormatVal(0); + sVal.SetValFalse(); } break; case IC_HEIGHT: diff --git a/src/game/items/CItemBase.cpp b/src/game/items/CItemBase.cpp index ad6fc1cf6..1d888e94a 100644 --- a/src/game/items/CItemBase.cpp +++ b/src/game/items/CItemBase.cpp @@ -1364,7 +1364,7 @@ bool CItemBase::r_WriteVal( lpctstr ptcKey, CSString & sVal, CTextConsole * pSrc return false; if ( !CCPropsItemWeapon::CanSubscribe(this)) - sVal.FormatVal(0); + sVal.SetValFalse(); else sVal.FormatVal( m_layer == LAYER_HAND2 ); break; diff --git a/src/game/items/CItemMulti.cpp b/src/game/items/CItemMulti.cpp index e4b8c7b87..01cf07eca 100644 --- a/src/game/items/CItemMulti.cpp +++ b/src/game/items/CItemMulti.cpp @@ -2690,7 +2690,7 @@ bool CItemMulti::r_WriteVal(lpctstr ptcKey, CSString & sVal, CTextConsole * pSrc break; } } - sVal.FormatVal(0); + sVal.SetValFalse(); break; } case SHL_REGION: diff --git a/src/game/items/CItemShip.cpp b/src/game/items/CItemShip.cpp index 620a02209..db9bea489 100644 --- a/src/game/items/CItemShip.cpp +++ b/src/game/items/CItemShip.cpp @@ -158,7 +158,7 @@ bool CItemShip::r_WriteVal(lpctstr ptcKey, CSString & sVal, CTextConsole * pSrc, if (pItemHold) sVal.FormatHex(pItemHold->GetUID()); else - sVal.FormatVal(0); + sVal.SetValFalse(); } break; case IMCS_PLANK: @@ -174,7 +174,7 @@ bool CItemShip::r_WriteVal(lpctstr ptcKey, CSString & sVal, CTextConsole * pSrc, if (pTiller) sVal.FormatHex(pTiller->GetUID()); else - sVal.FormatVal(0); + sVal.SetValFalse(); } break; default: diff --git a/src/game/items/CItemStone.cpp b/src/game/items/CItemStone.cpp index 506f95078..3a51112bf 100644 --- a/src/game/items/CItemStone.cpp +++ b/src/game/items/CItemStone.cpp @@ -492,7 +492,7 @@ bool CItemStone::r_WriteVal( lpctstr ptcKey, CSString & sVal, CTextConsole * pSr SKIP_SEPARATORS(pszCmd); CStoneMember * pMember = static_cast (GetContainerHead()); - sVal.FormatVal(0); + sVal.SetValFalse(); for ( int i = 0 ; pMember != nullptr; pMember = pMember->GetNext() ) { @@ -515,7 +515,7 @@ bool CItemStone::r_WriteVal( lpctstr ptcKey, CSString & sVal, CTextConsole * pSr else if ( !strnicmp("memberfromuid.", ptcKey, 14) ) { lpctstr pszCmd = ptcKey + 14; - sVal.FormatVal(0); + sVal.SetValFalse(); if ( !pszCmd[0] ) return true; @@ -580,7 +580,7 @@ bool CItemStone::r_WriteVal( lpctstr ptcKey, CSString & sVal, CTextConsole * pSr SKIP_SEPARATORS(pszCmd); CStoneMember * pMember = static_cast (GetContainerHead()); - sVal.FormatVal(0); + sVal.SetValFalse(); for ( int i = 0 ; pMember != nullptr; pMember = pMember->GetNext() ) { @@ -603,7 +603,7 @@ bool CItemStone::r_WriteVal( lpctstr ptcKey, CSString & sVal, CTextConsole * pSr else if ( !strnicmp("guildfromuid.", ptcKey, 13) ) { lpctstr pszCmd = ptcKey + 13; - sVal.FormatVal(0); + sVal.SetValFalse(); if ( !pszCmd[0] ) return true; From 08db71d5450ebff064c10f6178da596e80019b86 Mon Sep 17 00:00:00 2001 From: cbnolok Date: Fri, 4 Oct 2024 17:56:02 +0200 Subject: [PATCH 21/32] Fixed status updates to client not happening if the death process was aborted. --- src/game/CWorldTicker.cpp | 12 ++++++- src/game/chars/CChar.h | 22 +++++++++--- src/game/chars/CCharAct.cpp | 67 +++++++++++++++++++++++++------------ 3 files changed, 73 insertions(+), 28 deletions(-) diff --git a/src/game/CWorldTicker.cpp b/src/game/CWorldTicker.cpp index 31c6af85c..659c4e4cc 100644 --- a/src/game/CWorldTicker.cpp +++ b/src/game/CWorldTicker.cpp @@ -167,7 +167,6 @@ void CWorldTicker::_InsertCharTicking(const int64 iTickNext, CChar* pChar) std::unique_lock lock(_mCharTickList.MT_CMUTEX); #endif - _mCharTickList.emplace(iTickNext, pChar); pChar->_iTimePeriodicTick = iTickNext; } @@ -228,7 +227,18 @@ void CWorldTicker::AddCharTicking(CChar* pChar, bool fNeedsLock) } if (iTickNext == iTickOld) + { +/* +#ifdef _DEBUG + auto it = std::find_if(_mCharTickList.begin(), _mCharTickList.end(), + [pChar](const std::pair& elem) { + return elem.second == pChar; + }); + DEBUG_ASSERT(it == _mCharTickList.end()); +#endif +*/ return; + } //if (iTickNext < CWorldGameTime::GetCurrentTime().GetTimeRaw()) // We do that to get them tick as sooner as possible // return; diff --git a/src/game/chars/CChar.h b/src/game/chars/CChar.h index 67580ceab..3ea4fa13f 100644 --- a/src/game/chars/CChar.h +++ b/src/game/chars/CChar.h @@ -1177,16 +1177,28 @@ public: void StatFlag_Mod(uint64 uiStatFlag, bool fMod) noexcept; virtual void Update(const CClient* pClientExclude = nullptr) override; virtual void Flip() override; + + void EatAnim(CItem* pItem, ushort uiQty); + bool Reveal( uint64 iFlags = 0 ); + void Jail( CTextConsole * pSrc, bool fSet, int iCell ); bool SetPoison( int iSkill, int iHits, CChar * pCharSrc ); bool SetPoisonCure( bool fExtra ); bool CheckCorpseCrime( CItemCorpse *pCorpse, bool fLooting, bool fTest ); CItemCorpse * FindMyCorpse( bool fIgnoreLOS = false, int iRadius = 2) const; CItemCorpse * MakeCorpse( bool fFrontFall ); - bool RaiseCorpse( CItemCorpse * pCorpse ); - bool Death(); - bool Reveal( uint64 iFlags = 0 ); - void Jail( CTextConsole * pSrc, bool fSet, int iCell ); - void EatAnim(CItem* pItem, ushort uiQty); + bool RaiseCorpse( CItemCorpse * pCorpse ); + + enum class DeathRequestResult + { + Success, + SuccessAndDelete, + AlreadyDead, + Aborted, + AbortedNoLog + }; + + DeathRequestResult Death(); + /** * @Brief I'm calling guards (Player speech) * diff --git a/src/game/chars/CCharAct.cpp b/src/game/chars/CCharAct.cpp index 897a1e55d..e8d4c8269 100644 --- a/src/game/chars/CCharAct.cpp +++ b/src/game/chars/CCharAct.cpp @@ -4285,20 +4285,20 @@ void CChar::SleepStart( bool fFrontFall ) // Cleaning myself (dispel, cure, dismounting ...). // Creating the corpse ( MakeCorpse() ). // Removing myself from view, generating Death packets. -// RETURN: -// true = successfully died -// false = something went wrong? i'm an NPC, just delete (excepting BONDED ones). -bool CChar::Death() +CChar::DeathRequestResult CChar::Death() { ADDTOCALLSTACK("CChar::Death"); - if ( IsStatFlag(STATF_DEAD|STATF_INVUL) ) - return true; + if ( IsStatFlag(STATF_DEAD) ) + return DeathRequestResult::AlreadyDead; + + if ( IsStatFlag(STATF_INVUL) ) + return DeathRequestResult::AbortedNoLog; if ( IsTrigUsed(TRIGGER_DEATH) ) { if ( OnTrigger(CTRIG_Death, this) == TRIGRET_RET_TRUE ) - return true; + return DeathRequestResult::Aborted; } //Dismount now. Later is may be too late and cause problems if ( m_pNPC ) @@ -4353,7 +4353,8 @@ bool CChar::Death() iKillStrLen += snprintf( pszKillStr + iKillStrLen, Str_TempLength() - iKillStrLen, "%s%c'%s'.", - iKillers ? ", " : "", (pKiller->m_pPlayer) ? 'P':'N', pKiller->GetNameWithoutIncognito() ); + iKillers ? ", " : "", + (pKiller->m_pPlayer) ? 'P':'N', pKiller->GetNameWithoutIncognito() ); ++iKillers; } @@ -4361,7 +4362,7 @@ bool CChar::Death() // Record the kill event for posterity if ( !iKillers ) - iKillStrLen += snprintf( pszKillStr + iKillStrLen, Str_TempLength() - iKillStrLen, "accident." ); + /*iKillStrLen +=*/ snprintf( pszKillStr + iKillStrLen, Str_TempLength() - iKillStrLen, "accident." ); if ( m_pPlayer ) g_Log.Event( LOGL_EVENT|LOGM_KILLS, "%s\n", pszKillStr ); if ( m_pParty ) @@ -4385,7 +4386,7 @@ bool CChar::Death() } // Create the corpse item - bool fFrontFall = g_Rand.GetVal(2); + bool fFrontFall = g_Rand.GetValFast(2); CItemCorpse * pCorpse = MakeCorpse(fFrontFall); if ( pCorpse ) { @@ -4406,14 +4407,14 @@ bool CChar::Death() { m_CanMask |= CAN_C_GHOST; UpdateMode(nullptr, true); - return true; + return DeathRequestResult::Success; } if ( pCorpse ) pCorpse->m_uidLink.InitUID(); NPC_PetClearOwners(); - return false; // delete the NPC + return DeathRequestResult::SuccessAndDelete; // delete the NPC } if ( m_pPlayer ) @@ -4495,7 +4496,7 @@ bool CChar::Death() } } - return true; + return DeathRequestResult::Success; } // Check if we are held in place. @@ -5916,8 +5917,26 @@ bool CChar::OnTickPeriodic() */ if (!IsStatFlag(STATF_DEAD) && (Stat_GetVal(STAT_STR) <= 0)) { - EXC_SET_BLOCK("death"); - return Death(); + EXC_SET_BLOCK("death?"); + const DeathRequestResult deathRes = Death(); + if ((deathRes != DeathRequestResult::Aborted) && (deathRes != DeathRequestResult::AbortedNoLog)) + { + if (deathRes == DeathRequestResult::AlreadyDead) + goto do_status_update; + if (deathRes == DeathRequestResult::SuccessAndDelete) + return false; + return true; + } + else + { +#ifdef _DEBUG + if (deathRes != DeathRequestResult::AbortedNoLog) + { + g_Log.EventEvent("Aborted char '%s' (0x%" PRIx32 " ) death.\n", GetName(), GetUID().GetObjUID()); + } +#endif + ; // Then, fall through. + } } // Stats regeneration @@ -5935,18 +5954,21 @@ bool CChar::OnTickPeriodic() if (IsClientActive()) { CClient* pClient = GetClientActive(); + // Players have a silly "always run" flag that gets stuck on. if ( (iTimeCur - pClient->m_timeLastEventWalk) > (2 * MSECS_PER_TENTH) ) { StatFlag_Clear(STATF_FLY); } - // Show returning anim for thowing weapons after throw it - if ((pClient->m_timeLastSkillThrowing > 0) && ((iTimeCur - pClient->m_timeLastSkillThrowing) > (2 * MSECS_PER_TENTH))) - { - pClient->m_timeLastSkillThrowing = 0; - if (pClient->m_pSkillThrowingTarg->IsValidUID()) - Effect(EFFECT_BOLT, pClient->m_SkillThrowingAnimID, pClient->m_pSkillThrowingTarg, 18, 1, false, pClient->m_SkillThrowingAnimHue, pClient->m_SkillThrowingAnimRender); - } + + // Show returning anim for thowing weapons after throw it + if ((pClient->m_timeLastSkillThrowing > 0) && ((iTimeCur - pClient->m_timeLastSkillThrowing) > (2 * MSECS_PER_TENTH))) + { + pClient->m_timeLastSkillThrowing = 0; + if (pClient->m_pSkillThrowingTarg->IsValidUID()) + Effect(EFFECT_BOLT, pClient->m_SkillThrowingAnimID, pClient->m_pSkillThrowingTarg, 18, 1, false, pClient->m_SkillThrowingAnimHue, pClient->m_SkillThrowingAnimRender); + } + // Check targeting timeout, if set if ((pClient->m_Targ_Timeout > 0) && ((iTimeCur - pClient->m_Targ_Timeout) > 0) ) { @@ -5961,6 +5983,7 @@ bool CChar::OnTickPeriodic() CheckLocationEffects(true); } +do_status_update: EXC_SET_BLOCK("update stats"); OnTickStatusUpdate(); EXC_CATCH; From 17ccf65639b15eb63a9df926d8af47987eaed2b3 Mon Sep 17 00:00:00 2001 From: cbnolok Date: Fri, 4 Oct 2024 19:40:13 +0200 Subject: [PATCH 22/32] Refactored Windows SEH handling. --- src/common/CException.cpp | 36 ++++++++++++++++++------------------ src/common/CException.h | 25 +++++++++++++++++-------- src/game/spheresvr.cpp | 9 ++------- src/sphere/threads.cpp | 4 ++++ 4 files changed, 41 insertions(+), 33 deletions(-) diff --git a/src/common/CException.cpp b/src/common/CException.cpp index 5dcd8beac..6cb0b57c3 100644 --- a/src/common/CException.cpp +++ b/src/common/CException.cpp @@ -1,6 +1,10 @@ #include "CException.h" +#ifdef WINDOWS_SHOULD_EMIT_CRASH_DUMP +#include "crashdump/crashdump.h" +#endif + #ifndef _WIN32 #include //#include // for pthread_exit @@ -66,6 +70,7 @@ static bool* _GetAbortImmediate() noexcept static bool _fIsAbortImmediate = true; return &_fIsAbortImmediate; } + void SetAbortImmediate(bool on) noexcept { *_GetAbortImmediate() = on; @@ -84,6 +89,7 @@ void RaiseRecoverableAbort() SetAbortImmediate(false); std::abort(); } + [[noreturn]] void RaiseImmediateAbort() { @@ -189,16 +195,16 @@ bool CAssert::GetErrorMessage(lptstr lpszError, uint uiMaxError) const #ifdef _WIN32 -CWinException::CWinException(uint uCode, size_t pAddress) : +CWinStructuredException::CWinStructuredException(uint uCode, size_t pAddress) : CSError(LOGL_CRIT, uCode, "Exception"), m_pAddress(pAddress) { } -CWinException::~CWinException() +CWinStructuredException::~CWinStructuredException() { } -bool CWinException::GetErrorMessage(lptstr lpszError, uint uiMaxError) const +bool CWinStructuredException::GetErrorMessage(lptstr lpszError, uint uiMaxError) const { lpctstr zMsg; switch ( m_hError ) @@ -238,7 +244,7 @@ static void _cdecl Sphere_Purecall_Handler() void SetPurecallHandler() { // We don't want sphere to immediately exit if something calls a pure virtual method. -#ifdef MSVC_RUNTIME +#ifdef MSVC_COMPILER _set_purecall_handler(Sphere_Purecall_Handler); #else // GCC handler for pure calls is __cxxabiv1::__cxa_pure_virtual. @@ -247,34 +253,28 @@ void SetPurecallHandler() #endif } -#if defined(_WIN32) && !defined(_DEBUG) - -#include "crashdump/crashdump.h" - -static void _cdecl Sphere_Exception_Windows( unsigned int id, struct _EXCEPTION_POINTERS* pData ) +#ifdef WINDOWS_SEH_EXCEPTION_MODEL +static void _cdecl Sphere_Structured_Exception_Windows( unsigned int id, struct _EXCEPTION_POINTERS* pData ) { -#ifndef _NO_CRASHDUMP +# ifdef WINDOWS_SHOULD_EMIT_CRASH_DUMP if ( CrashDump::IsEnabled() ) CrashDump::StartCrashDump(GetCurrentProcessId(), GetCurrentThreadId(), pData); +# endif -#endif // WIN32 gets an exception. size_t pCodeStart = (size_t)(byte *) &globalstartsymbol; // sync up to my MAP file. size_t pAddr = (size_t)pData->ExceptionRecord->ExceptionAddress; pAddr -= pCodeStart; - throw CWinException(id, pAddr); + throw CWinStructuredException(id, pAddr); } -#endif // _WIN32 && !_DEBUG - -void SetExceptionTranslator() +void SetWindowsStructuredExceptionTranslator() { -#ifdef MSVC_COMPILER - _set_se_translator( Sphere_Exception_Windows ); -#endif + _set_se_translator( Sphere_Structured_Exception_Windows ); } +#endif #ifndef _WIN32 static void _cdecl Signal_Hangup(int sig = 0) noexcept // If shutdown is initialized diff --git a/src/common/CException.h b/src/common/CException.h index 99543be87..71e8464d2 100644 --- a/src/common/CException.h +++ b/src/common/CException.h @@ -9,6 +9,17 @@ //#include "../sphere/threads.h" #include "CLog.h" +#if defined(_WIN32) && (defined(MSVC_COMPILER) || (defined(__MINGW32__) && defined(__SEH__))) +# define WINDOWS_SEH_EXCEPTION_MODEL 1 +#endif + +#if defined(WINDOWS_SEH_EXCEPTION_MODEL) && defined(_NIGHTLYBUILD) && !defined(_NO_CRASHDUMP) +// We don't want this for Release build because, in order to call _set_se_translator, we should set the /EHa +// compiler flag, which slows down code a bit. +// Also, the crash dump generating code works only when Structured Exception Handling is enabled +# define WINDOWS_SHOULD_EMIT_CRASH_DUMP 1 +#endif + // ------------------------------------------------------------------- // ------------------------------------------------------------------- @@ -18,7 +29,7 @@ extern "C" } void SetPurecallHandler(); -void SetExceptionTranslator(); +void SetWindowsStructuredExceptionTranslator(); #ifndef _WIN32 void SetUnixSignals( bool ); @@ -79,20 +90,18 @@ class CAssert : public CSError virtual bool GetErrorMessage(lptstr lpszError, uint uiMaxError ) const override; }; -#ifdef _WIN32 +#ifdef WINDOWS_SEH_EXCEPTION_MODEL // Catch and get details on the system exceptions. - class CWinException : public CSError + class CWinStructuredException : public CSError { public: static const char *m_sClassName; const size_t m_pAddress; - CWinException(uint uCode, size_t pAddress); - virtual ~CWinException(); - private: - CWinException& operator=(const CWinException& other); + CWinStructuredException(uint uCode, size_t pAddress); + virtual ~CWinStructuredException(); + CWinStructuredException& operator=(const CWinStructuredException& other) = delete; - public: virtual bool GetErrorMessage(lptstr lpszError, uint nMaxError) const override; }; #endif diff --git a/src/game/spheresvr.cpp b/src/game/spheresvr.cpp index 38b696f56..be7f4c857 100644 --- a/src/game/spheresvr.cpp +++ b/src/game/spheresvr.cpp @@ -71,12 +71,8 @@ GlobalInitializer::GlobalInitializer() //--- Exception handling - // Set exception catcher? -#if defined(MSVC_COMPILER) && !defined(_NIGHTLYBUILD) - // We don't need an exception translator for the Debug build, since that build would, generally, be used with a debugger. - // We don't want that for Release build either because, in order to call _set_se_translator, we should set the /EHa - // compiler flag, which slows down code a bit. - SetExceptionTranslator(); +#ifdef WINDOWS_SEH_EXCEPTION_MODEL + SetWindowsStructuredExceptionTranslator(); #endif // Set function to handle the invalid case where a pure virtual function is called. @@ -192,7 +188,6 @@ MainThread::MainThread() void MainThread::onStart() { AbstractSphereThread::onStart(); - SetExceptionTranslator(); } void MainThread::tick() diff --git a/src/sphere/threads.cpp b/src/sphere/threads.cpp index 9eb3d26f6..7c9306885 100644 --- a/src/sphere/threads.cpp +++ b/src/sphere/threads.cpp @@ -643,6 +643,10 @@ void AbstractThread::onStart() // when implemented in derived classes this method must always be called too, preferably before // the custom implementation +#ifdef WINDOWS_SEH_EXCEPTION_MODEL + SetWindowsStructuredExceptionTranslator(); +#endif + // we set the id here to ensure it is available before the first tick, otherwise there's // a small delay when setting it from AbstractThread::start and it's possible for the id // to not be set fast enough (particular when using pthreads) From af6516e5884168436385f31d9d0495a0384474b7 Mon Sep 17 00:00:00 2001 From: cbnolok Date: Sat, 5 Oct 2024 11:51:42 +0200 Subject: [PATCH 23/32] Fixed Windows compilation warning on Debug build, refactored _MAX_PATH. --- README.md | 4 ++-- src/common/CException.cpp | 4 ++-- src/common/CException.h | 12 +++++++--- src/common/CLog.cpp | 4 +--- src/common/CLog.h | 2 -- src/common/CScript.cpp | 8 +++---- src/common/CUOInstall.cpp | 2 +- src/common/CVarDefMap.cpp | 1 - src/common/common.h | 3 ++- src/common/os_unix.h | 22 +++++++++++++++--- src/common/os_windows.h | 12 +++++++++- src/common/resource/CResourceHolder.cpp | 12 +++++----- src/common/resource/CResourceHolder.h | 7 ------ src/common/resource/CResourceRef.cpp | 10 ++++++-- src/common/resource/sections/CWebPageDef.cpp | 6 ++--- src/common/sphere_library/CSFile.cpp | 2 +- src/common/sphere_library/CSFileList.cpp | 12 +++++----- src/common/sphere_library/CSWindow.cpp | 2 +- src/game/CServer.cpp | 24 ++++++++++---------- src/game/CServerConfig.cpp | 8 +++---- src/game/CWorld.cpp | 16 ++++++------- src/game/CWorldImport.cpp | 4 ++-- src/game/chars/CCharAct.cpp | 4 ++-- src/game/clients/CAccount.cpp | 6 ++--- src/game/clients/CClientLog.cpp | 4 ++-- src/game/clients/CClientMsg.cpp | 4 ++-- src/game/spheresvr.cpp | 2 +- src/sphere/ntservice.cpp | 2 +- src/sphere/ntwindow.cpp | 4 ++-- src/sphere/threads.cpp | 2 +- 30 files changed, 116 insertions(+), 89 deletions(-) diff --git a/README.md b/README.md index 67aabfb3a..d2f5e46fa 100644 --- a/README.md +++ b/README.md @@ -72,7 +72,7 @@ Most notable changes (right now) are: ### Required libraries (Windows) -+ `libmariadb.dll` (MariaDB Client v10.*package), found in `lib/bin/*cpu_architecture*/mariadb/libmariadb.dll` ++ `libmariadb.dll` (MariaDB Client v10.\* package), found in `lib/bin/*cpu_architecture*/mariadb/libmariadb.dll` ### Required libraries (Linux) @@ -156,7 +156,7 @@ Building will require more packages than the ones needed to run Sphere. #### Compiling on Linux -Just run the `make` command inside the `build` folder. You can pass the -jX argument (`make -jX`, where X is a number) to speed up the compilation and split the work between X threads. +Just run `cmake --build .` in the build directory (the one where you have asked CMake to create its files). ## Coding Notes (add as you wish to standardize the coding for new contributors) diff --git a/src/common/CException.cpp b/src/common/CException.cpp index 6cb0b57c3..202463459 100644 --- a/src/common/CException.cpp +++ b/src/common/CException.cpp @@ -193,7 +193,7 @@ bool CAssert::GetErrorMessage(lptstr lpszError, uint uiMaxError) const // -------------------------------------------------------------------------------- // -------------------------------------------------------------------------------- -#ifdef _WIN32 +#ifdef WINDOWS_SPHERE_SHOULD_HANDLE_STRUCTURED_EXCEPTIONS CWinStructuredException::CWinStructuredException(uint uCode, size_t pAddress) : CSError(LOGL_CRIT, uCode, "Exception"), m_pAddress(pAddress) @@ -253,7 +253,7 @@ void SetPurecallHandler() #endif } -#ifdef WINDOWS_SEH_EXCEPTION_MODEL +#ifdef WINDOWS_SPHERE_SHOULD_HANDLE_STRUCTURED_EXCEPTIONS static void _cdecl Sphere_Structured_Exception_Windows( unsigned int id, struct _EXCEPTION_POINTERS* pData ) { # ifdef WINDOWS_SHOULD_EMIT_CRASH_DUMP diff --git a/src/common/CException.h b/src/common/CException.h index 71e8464d2..b141afcd3 100644 --- a/src/common/CException.h +++ b/src/common/CException.h @@ -10,12 +10,16 @@ #include "CLog.h" #if defined(_WIN32) && (defined(MSVC_COMPILER) || (defined(__MINGW32__) && defined(__SEH__))) -# define WINDOWS_SEH_EXCEPTION_MODEL 1 +# define WINDOWS_HAS_SEH 1 #endif -#if defined(WINDOWS_SEH_EXCEPTION_MODEL) && defined(_NIGHTLYBUILD) && !defined(_NO_CRASHDUMP) +#if defined (WINDOWS_HAS_SEH) && defined(_NIGHTLYBUILD) // We don't want this for Release build because, in order to call _set_se_translator, we should set the /EHa // compiler flag, which slows down code a bit. +# define WINDOWS_SPHERE_SHOULD_HANDLE_STRUCTURED_EXCEPTIONS 1 +#endif + +#if defined(WINDOWS_SPHERE_SHOULD_HANDLE_STRUCTURED_EXCEPTIONS) && !defined(_NO_CRASHDUMP) // Also, the crash dump generating code works only when Structured Exception Handling is enabled # define WINDOWS_SHOULD_EMIT_CRASH_DUMP 1 #endif @@ -29,7 +33,9 @@ extern "C" } void SetPurecallHandler(); +#ifdef WINDOWS_SPHERE_SHOULD_HANDLE_STRUCTURED_EXCEPTIONS void SetWindowsStructuredExceptionTranslator(); +#endif #ifndef _WIN32 void SetUnixSignals( bool ); @@ -90,7 +96,7 @@ class CAssert : public CSError virtual bool GetErrorMessage(lptstr lpszError, uint uiMaxError ) const override; }; -#ifdef WINDOWS_SEH_EXCEPTION_MODEL +#ifdef WINDOWS_SPHERE_SHOULD_HANDLE_STRUCTURED_EXCEPTIONS // Catch and get details on the system exceptions. class CWinStructuredException : public CSError { diff --git a/src/common/CLog.cpp b/src/common/CLog.cpp index 4e90575ae..926dde738 100644 --- a/src/common/CLog.cpp +++ b/src/common/CLog.cpp @@ -75,7 +75,6 @@ int CEventLog::EventCustom(ConsoleTextColor iColor, dword dwMask, lpctstr pszFor return iret; } -#ifdef _DEBUG int CEventLog::EventEvent(lpctstr pszFormat, ...) noexcept { va_list vargs; @@ -84,7 +83,6 @@ int CEventLog::EventEvent(lpctstr pszFormat, ...) noexcept va_end(vargs); return iret; } -#endif //_DEBUG //------- @@ -265,7 +263,7 @@ int CLog::EventStr( dword dwMask, lpctstr pszMsg, ConsoleTextColor iLogColor) no } // Get the script context. (if there is one) - tchar szScriptContext[ _MAX_PATH + 16 ]; + tchar szScriptContext[ SPHERE_MAX_PATH + 16 ]; if ( !(dwMask & LOGM_NOCONTEXT) && m_pScriptContext ) { CScriptLineContext LineContext = m_pScriptContext->GetContext(); diff --git a/src/common/CLog.h b/src/common/CLog.h index a362e5ccc..fbb650620 100644 --- a/src/common/CLog.h +++ b/src/common/CLog.h @@ -71,9 +71,7 @@ class CEventLog int _cdecl EventError(lpctstr pszFormat, ...) noexcept __printfargs(2,3); int _cdecl EventWarn(lpctstr pszFormat, ...) noexcept __printfargs(2,3); int _cdecl EventCustom(ConsoleTextColor iColor, dword dwMask, lpctstr pszFormat, ...) noexcept __printfargs(4,5); -#ifdef _DEBUG int _cdecl EventEvent( lpctstr pszFormat, ... ) noexcept __printfargs(2,3); -#endif //_DEBUG CEventLog(); virtual ~CEventLog(); diff --git a/src/common/CScript.cpp b/src/common/CScript.cpp index 645ad19a0..352bc1680 100644 --- a/src/common/CScript.cpp +++ b/src/common/CScript.cpp @@ -374,7 +374,7 @@ bool CScriptKeyAlloc::ParseKey( lpctstr ptcKey, lpctstr pszVal ) if (ptcKey != m_pszKey) { // Invalid key, or not yet inited. - strcpy(m_pszKey, ptcKey); + Str_CopyLimitNull(m_pszKey, ptcKey, m_Mem.GetDataLength()); } m_pszArg = m_pszKey + lenkey; @@ -490,9 +490,9 @@ bool CScript::_Open( lpctstr ptcFilename, uint uiFlags ) lpctstr ptcExt = GetFilesExt(ptcFilename); if ( !ptcExt ) { - tchar ptcTemp[_MAX_PATH]; - Str_CopyLimit(ptcTemp, ptcFilename, _MAX_PATH-4); // -4 beause of SPHERE_SCRIPT, which is = ".scp" - strcat(ptcTemp, SPHERE_SCRIPT); + tchar ptcTemp[SPHERE_MAX_PATH]; + const size_t uiCopied = Str_CopyLimit(ptcTemp, ptcFilename, sizeof(ptcTemp) - SPHERE_SCRIPT_EXT_LEN); + Str_ConcatLimitNull(ptcTemp, SPHERE_SCRIPT_EXT, sizeof(ptcTemp) - uiCopied); _SetFilePath(ptcTemp); uiFlags |= OF_TEXT; } diff --git a/src/common/CUOInstall.cpp b/src/common/CUOInstall.cpp index 2240ced2c..f09727661 100644 --- a/src/common/CUOInstall.cpp +++ b/src/common/CUOInstall.cpp @@ -58,7 +58,7 @@ bool CUOInstall::FindInstall() return false; } - tchar szValue[ _MAX_PATH ]; + tchar szValue[ SPHERE_MAX_PATH ]; DWORD lSize = sizeof( szValue ); DWORD dwType = REG_SZ; lRet = RegQueryValueEx(hKey, "ExePath", nullptr, &dwType, (byte*)szValue, &lSize); diff --git a/src/common/CVarDefMap.cpp b/src/common/CVarDefMap.cpp index 3e99fae28..09d2b452b 100644 --- a/src/common/CVarDefMap.cpp +++ b/src/common/CVarDefMap.cpp @@ -2,7 +2,6 @@ #include "../common/CLog.h" #include "../game/CServer.h" #include "../game/CServerConfig.h" -#include "CException.h" #include "CExpression.h" #include "CScript.h" #include "CTextConsole.h" diff --git a/src/common/common.h b/src/common/common.h index fdf5a2f9e..deb52d81e 100644 --- a/src/common/common.h +++ b/src/common/common.h @@ -12,7 +12,8 @@ #define SPHERE_FILE "sphere" // file name prefix #define SPHERE_TITLE "SphereServer" -#define SPHERE_SCRIPT ".scp" +#define SPHERE_SCRIPT_EXT ".scp" +#define SPHERE_SCRIPT_EXT_LEN 4 #define SCRIPT_MAX_LINE_LEN 4096 // default size. #define SCRIPT_MAX_SECTION_LEN 128 diff --git a/src/common/os_unix.h b/src/common/os_unix.h index 684fba9ad..492ce9cd7 100644 --- a/src/common/os_unix.h +++ b/src/common/os_unix.h @@ -6,21 +6,37 @@ #ifndef _INC_OS_UNIX_H #define _INC_OS_UNIX_H +//#include // PATH_MAX #include // usleep #include // toupper, tolower //#define SLASH_PATH "/" -#ifndef _MAX_PATH // stdlib.h ? - #define _MAX_PATH 260 // max. length of full pathname + +// Max. length of full pathname + +/* +#if defined(PATH_MAX) // limits.h +# if PATH_MAX <= 0 +# define SPHERE_MAX_PATH 260 +# elif PATH_MAX > 1024 +# define SPHERE_MAX_PATH 1024 // Define a "big enough" max value, just to avoid the need of enormous char buffers. +# else +# define SPHERE_MAX_PATH PATH_MAX +# endif +#else +// If we want to keep compatibility with legacy Windows max path length. +# define SPHERE_MAX_PATH 260 #endif +*/ +// TODO: enable longer MAX_PATHs on both Linux and Windows, also checking that increasing that limit doesn't cause any buffer overflow. +#define SPHERE_MAX_PATH 260 #define _cdecl #define __cdecl #define FAR #define E_FAIL 0x80004005 // exception code -#define HANDLE dword /* cross-platform functions macros */ diff --git a/src/common/os_windows.h b/src/common/os_windows.h index 5a0d456e1..13e39d1b5 100644 --- a/src/common/os_windows.h +++ b/src/common/os_windows.h @@ -6,6 +6,17 @@ #ifndef _INC_OS_WINDOWS_H #define _INC_OS_WINDOWS_H +// Windows keeps this reduced limit for compatibility with older API calls and FAT32 path length... +// this limit includes the total length of the path, such as directories, subdirectories, and the filename, +// and it is constrained to 259 characters for the path itself, with the 260th character being reserved for the null terminator. +// On newer versions, Even though long paths are supported (via path prefix or application manifest - if Vista+), +// _MAX_PATH is not updated to reflect the new maximum path length (which can now be up to 32,767 characters). +// The long path feature requires the usage of the wide-character WinAPI calls and the \\?\ prefix. +#ifdef _MAX_PATH +# define SPHERE_MAX_PATH _MAX_PATH +#else +# define SPHERE_MAX_PATH 260 +#endif // _WIN32_WINNT version constants /* @@ -27,7 +38,6 @@ #define _WIN32_WINNT 0x0501 // By default we target Windows XP #endif - #undef FD_SETSIZE #define FD_SETSIZE 1024 // for max of n users ! default = 64 (FD: file descriptor) diff --git a/src/common/resource/CResourceHolder.cpp b/src/common/resource/CResourceHolder.cpp index 621628f1a..ea3322cfa 100644 --- a/src/common/resource/CResourceHolder.cpp +++ b/src/common/resource/CResourceHolder.cpp @@ -104,13 +104,13 @@ CResourceScript * CResourceHolder::AddResourceFile( lpctstr pszName ) ASSERT(pszName != nullptr); // Is this really just a dir name ? - if (strlen(pszName) >= _MAX_PATH) + if (strlen(pszName) >= SPHERE_MAX_PATH) throw CSError(LOGL_ERROR, 0, "Filename too long!"); - tchar szName[_MAX_PATH]; + tchar szName[SPHERE_MAX_PATH]; Str_CopyLimitNull(szName, pszName, sizeof(szName)); - tchar szTitle[_MAX_PATH]; + tchar szTitle[SPHERE_MAX_PATH]; lpctstr ptcTitle = CScript::GetFilesTitle(szName); ASSERT_ALWAYS(strlen(ptcTitle) < sizeof(szTitle)); Str_CopyLimitNull(szTitle, ptcTitle, sizeof(szTitle)); @@ -125,8 +125,8 @@ CResourceScript * CResourceHolder::AddResourceFile( lpctstr pszName ) if ( pszExt == nullptr ) { // No file extension provided, so append .scp to the filename - Str_ConcatLimitNull( szName, SPHERE_SCRIPT, sizeof(szName) ); - Str_ConcatLimitNull( szTitle, SPHERE_SCRIPT, sizeof(szTitle) ); + Str_ConcatLimitNull( szName, SPHERE_SCRIPT_EXT, sizeof(szName) ); + Str_ConcatLimitNull( szTitle, SPHERE_SCRIPT_EXT, sizeof(szTitle) ); } if ( ! strnicmp( szTitle, SPHERE_FILE "tables", strlen(SPHERE_FILE "tables"))) @@ -159,7 +159,7 @@ void CResourceHolder::AddResourceDir( lpctstr pszDirName ) if ( pszDirName[0] == '\0' ) return; - CSString sFilePath = CSFile::GetMergedFileName( pszDirName, "*" SPHERE_SCRIPT ); + CSString sFilePath = CSFile::GetMergedFileName( pszDirName, "*" SPHERE_SCRIPT_EXT ); CSFileList filelist; int iRet = filelist.ReadDir( sFilePath, false ); diff --git a/src/common/resource/CResourceHolder.h b/src/common/resource/CResourceHolder.h index a5c4b40d5..f4e5f8b33 100644 --- a/src/common/resource/CResourceHolder.h +++ b/src/common/resource/CResourceHolder.h @@ -71,11 +71,4 @@ class CResourceHolder : public CScriptObj CResourceHolder& operator=(const CResourceHolder& other) = delete; }; -inline lpctstr CResourceHolder::GetResourceBlockName( RES_TYPE restype ) // static -{ - if ( restype < 0 || restype >= RES_QTY ) - restype = RES_UNKNOWN; - return( sm_szResourceBlocks[restype] ); -} - #endif // _INC_CResourceHolder_H diff --git a/src/common/resource/CResourceRef.cpp b/src/common/resource/CResourceRef.cpp index 500a427ee..1697734d2 100644 --- a/src/common/resource/CResourceRef.cpp +++ b/src/common/resource/CResourceRef.cpp @@ -84,7 +84,6 @@ bool CResourceRefArray::r_LoadVal( CScript & s, RES_TYPE restype ) int iArgCount = Str_ParseCmds( pszCmd, ppBlocks, ARRAY_COUNT(ppBlocks)); for ( int i = 0; i < iArgCount; ++i ) { - std::shared_ptr pResourceDefRef; CResourceLink* pResourceLink = nullptr; pszCmd = ppBlocks[i]; @@ -128,7 +127,7 @@ bool CResourceRefArray::r_LoadVal( CScript & s, RES_TYPE restype ) if (pResourceLink == nullptr) { fRet = false; - DEBUG_ERR(("Unknown '%s' Resource '%s'\n", CResourceHolder::GetResourceBlockName(restype), pszCmd)); + g_Log.EventError("Unknown '%s' Resource '%s'\n", CResourceHolder::GetResourceBlockName(restype), pszCmd); } } @@ -198,6 +197,13 @@ size_t CResourceRefArray::FindResourceName( RES_TYPE restype, lpctstr ptcKey ) c return FindResourceID(pResourceLink->GetResourceID()); } +lpctstr CResourceHolder::GetResourceBlockName( RES_TYPE restype ) // static +{ + if ( restype < 0 || restype >= RES_QTY ) + restype = RES_UNKNOWN; + return sm_szResourceBlocks[restype]; +} + void CResourceRefArray::r_Write( CScript & s, lpctstr ptcKey ) const { ADDTOCALLSTACK_DEBUG("CResourceRefArray::r_Write"); diff --git a/src/common/resource/sections/CWebPageDef.cpp b/src/common/resource/sections/CWebPageDef.cpp index 9816ad0ef..518f17875 100644 --- a/src/common/resource/sections/CWebPageDef.cpp +++ b/src/common/resource/sections/CWebPageDef.cpp @@ -390,8 +390,8 @@ void CWebPageDef::WebPageLog() lpctstr pszExt = FileRead.GetFileExt(); - tchar szName[ _MAX_PATH ]; - Str_CopyLimitNull( szName, m_sDstFilePath, _MAX_PATH); + tchar szName[ SPHERE_MAX_PATH ]; + Str_CopyLimitNull( szName, m_sDstFilePath, SPHERE_MAX_PATH); szName[ m_sDstFilePath.GetLength() - strlen(pszExt) ] = '\0'; CSTime datetime = CSTime::GetCurrentTime(); @@ -780,7 +780,7 @@ void CWebPageDef::ServPage( CClient * pClient, tchar * pszPage, CSTime * pdateIf ADDTOCALLSTACK("CWebPageDef::ServPage"); // make sure this is a valid format for the request. - tchar szPageName[_MAX_PATH]; + tchar szPageName[SPHERE_MAX_PATH]; Str_GetBare( szPageName, pszPage, sizeof(szPageName), "!\"#$%&()*,:;<=>?[]^{|}-+'`" ); int iError = 404; diff --git a/src/common/sphere_library/CSFile.cpp b/src/common/sphere_library/CSFile.cpp index 27788a0a4..42d3bf124 100644 --- a/src/common/sphere_library/CSFile.cpp +++ b/src/common/sphere_library/CSFile.cpp @@ -434,7 +434,7 @@ CSString CSFile::GetMergedFileName( lpctstr pszBase, lpctstr pszName ) // static ADDTOCALLSTACK("CSFile::GetMergedFileName"); // Merge path and file name. - tchar ptcFilePath[ _MAX_PATH ]; + tchar ptcFilePath[ SPHERE_MAX_PATH ]; size_t len = 0; if ( pszBase && pszBase[0] ) { diff --git a/src/common/sphere_library/CSFileList.cpp b/src/common/sphere_library/CSFileList.cpp index bf3c46457..997540b25 100644 --- a/src/common/sphere_library/CSFileList.cpp +++ b/src/common/sphere_library/CSFileList.cpp @@ -56,7 +56,7 @@ int CSFileList::ReadDir( lpctstr pszFileDir, bool bShowError ) { ADDTOCALLSTACK("CSFileList::ReadDir"); // NOTE: It seems NOT to like the trailing \ alone - tchar szFileDir[_MAX_PATH]; + tchar szFileDir[SPHERE_MAX_PATH]; size_t len = Str_CopyLen(szFileDir, pszFileDir); #ifdef _WIN32 if ( len > 0 ) @@ -73,7 +73,7 @@ int CSFileList::ReadDir( lpctstr pszFileDir, bool bShowError ) if ( lFind == -1 ) #else - char szFilename[_MAX_PATH]; + char szFilename[SPHERE_MAX_PATH]; // Need to strip out the *.scp part for ( size_t i = len; i > 0; --i ) { @@ -110,15 +110,15 @@ int CSFileList::ReadDir( lpctstr pszFileDir, bool bShowError ) if ( fileinfo->d_name[0] == '.' ) continue; - const int ret = snprintf(szFilename, _MAX_PATH, "%s%s", szFileDir, fileinfo->d_name); - szFilename[_MAX_PATH - 1] = '\0'; - if ((ret < 0) || (ret > _MAX_PATH - 1)) + const int ret = snprintf(szFilename, SPHERE_MAX_PATH, "%s%s", szFileDir, fileinfo->d_name); + szFilename[SPHERE_MAX_PATH - 1] = '\0'; + if ((ret < 0) || (ret > SPHERE_MAX_PATH - 1)) { g_Log.EventError("Unable to concatenate the path (too long). Current file '%s'.\n", fileinfo->d_name); break; } len = strlen(szFilename); - if ( len > 4 && !strcmpi(&szFilename[len - 4], SPHERE_SCRIPT) ) + if ( (len > SPHERE_SCRIPT_EXT_LEN) && !strcmpi(&szFilename[len - SPHERE_SCRIPT_EXT_LEN], SPHERE_SCRIPT_EXT) ) AddTail(fileinfo->d_name); #endif } diff --git a/src/common/sphere_library/CSWindow.cpp b/src/common/sphere_library/CSWindow.cpp index 09c0da251..2b1dca8dd 100644 --- a/src/common/sphere_library/CSWindow.cpp +++ b/src/common/sphere_library/CSWindow.cpp @@ -252,7 +252,7 @@ void CWinApp::InitInstance(LPCTSTR pszAppName, HINSTANCE hInstance, LPTSTR lpszC m_hInstance = hInstance; m_lpCmdLine = lpszCmdLine; - char szFileName[_MAX_PATH]; + char szFileName[SPHERE_MAX_PATH]; if (! GetModuleFileName(m_hInstance, szFileName, sizeof(szFileName))) return; m_pszExeName = szFileName; diff --git a/src/game/CServer.cpp b/src/game/CServer.cpp index 5b9bc5bca..5e35bacd6 100644 --- a/src/game/CServer.cpp +++ b/src/game/CServer.cpp @@ -79,7 +79,7 @@ static void defragSphere(char *path) CSFileText inf; CSFile ouf; char file_buf[1024]; - char path_buf[_MAX_PATH], path_buf_2[_MAX_PATH]; + char path_buf[SPHERE_MAX_PATH], path_buf_2[SPHERE_MAX_PATH]; char *str_ptr = nullptr, *str_ptr_2 = nullptr; g_Log.Event(LOGM_INIT, "Defragmentation (UID alteration) of " SPHERE_TITLE " saves.\n" @@ -95,9 +95,9 @@ static void defragSphere(char *path) for ( uint i = 0; i < 3; ++i ) { Str_CopyLimitNull(path_buf, path, sizeof(path_buf)); - if ( i == 0 ) strcat(path_buf, SPHERE_FILE "statics" SPHERE_SCRIPT); - else if ( i == 1 ) strcat(path_buf, SPHERE_FILE "world" SPHERE_SCRIPT); - else strcat(path_buf, SPHERE_FILE "chars" SPHERE_SCRIPT); + if ( i == 0 ) strcat(path_buf, SPHERE_FILE "statics" SPHERE_SCRIPT_EXT); + else if ( i == 1 ) strcat(path_buf, SPHERE_FILE "world" SPHERE_SCRIPT_EXT); + else strcat(path_buf, SPHERE_FILE "chars" SPHERE_SCRIPT_EXT); g_Log.Event(LOGM_INIT, "Reading current UIDs: %s\n", path_buf); if ( !inf.Open(path_buf, OF_READ|OF_TEXT|OF_DEFAULTMODE) ) @@ -145,10 +145,10 @@ static void defragSphere(char *path) { Str_CopyLimitNull(path_buf, path, sizeof(path_buf)); if ( !i ) strcat(path_buf, SPHERE_FILE "accu.scp"); - else if ( i == 1 ) strcat(path_buf, SPHERE_FILE "chars" SPHERE_SCRIPT); - else if ( i == 2 ) strcat(path_buf, SPHERE_FILE "data" SPHERE_SCRIPT); - else if ( i == 3 ) strcat(path_buf, SPHERE_FILE "world" SPHERE_SCRIPT); - else if ( i == 4 ) strcat(path_buf, SPHERE_FILE "statics" SPHERE_SCRIPT); + else if ( i == 1 ) strcat(path_buf, SPHERE_FILE "chars" SPHERE_SCRIPT_EXT); + else if ( i == 2 ) strcat(path_buf, SPHERE_FILE "data" SPHERE_SCRIPT_EXT); + else if ( i == 3 ) strcat(path_buf, SPHERE_FILE "world" SPHERE_SCRIPT_EXT); + else if ( i == 4 ) strcat(path_buf, SPHERE_FILE "statics" SPHERE_SCRIPT_EXT); g_Log.Event(LOGM_INIT, "Updating UID-s in %s to %s.new\n", path_buf, path_buf); if ( !inf.Open(path_buf, OF_READ|OF_TEXT|OF_DEFAULTMODE) ) { @@ -1116,7 +1116,7 @@ bool CServer::OnConsoleCmd( CSString & sText, CTextConsole * pSrc ) if ( !strnicmp(pszText, "strip tng", 9) || !strnicmp(pszText, "tngstrip", 8)) { Str_CopyLimitNull(z, dirname, Str_TempLength()); - Str_ConcatLimitNull(z, "sphere_strip_tng" SPHERE_SCRIPT, Str_TempLength()); + Str_ConcatLimitNull(z, "sphere_strip_tng" SPHERE_SCRIPT_EXT, Str_TempLength()); if (pSrc != this) { pSrc->SysMessagef("StripFile is %s.\n", z); @@ -1198,7 +1198,7 @@ bool CServer::OnConsoleCmd( CSString & sText, CTextConsole * pSrc ) else if ( !strnicmp(pszText, "strip axis", 10) || !strnicmp(pszText, "strip", 5) ) { Str_CopyLimitNull(z, dirname, Str_TempLength()); - Str_ConcatLimitNull(z, "sphere_strip_axis" SPHERE_SCRIPT, Str_TempLength()); + Str_ConcatLimitNull(z, "sphere_strip_axis" SPHERE_SCRIPT_EXT, Str_TempLength()); if (pSrc != this) { pSrc->SysMessagef("StripFile is %s.\n", z); @@ -2494,7 +2494,7 @@ bool CServer::SocketsInit() // Initialize sockets // What are we listing our port as to the world. // Tell the admin what we know. - tchar szName[ _MAX_PATH ]; + tchar szName[ SPHERE_MAX_PATH ]; struct hostent * pHost = nullptr; int iRet = gethostname(szName, sizeof(szName)); @@ -2504,7 +2504,7 @@ bool CServer::SocketsInit() // Initialize sockets { pHost = gethostbyname(szName); if ( pHost && pHost->h_addr && pHost->h_name && pHost->h_name[0] ) - Str_CopyLimitNull(szName, pHost->h_name, _MAX_PATH); + Str_CopyLimitNull(szName, pHost->h_name, SPHERE_MAX_PATH); } g_Log.Event( LOGM_INIT, "Server started on hostname '%s'\n", szName); diff --git a/src/game/CServerConfig.cpp b/src/game/CServerConfig.cpp index 2cf770e64..6beadd6bd 100644 --- a/src/game/CServerConfig.cpp +++ b/src/game/CServerConfig.cpp @@ -4685,13 +4685,13 @@ bool CServerConfig::Load( bool fResync ) // Now load the *TABLES.SCP file. if ( ! fResync ) { - if ( ! OpenResourceFind( m_scpTables, SPHERE_FILE "tables" SPHERE_SCRIPT )) + if ( ! OpenResourceFind( m_scpTables, SPHERE_FILE "tables" SPHERE_SCRIPT_EXT )) { - g_Log.Event( LOGL_FATAL|LOGM_INIT, "Error opening table definitions file (" SPHERE_FILE "tables" SPHERE_SCRIPT ")...\n" ); + g_Log.Event( LOGL_FATAL|LOGM_INIT, "Error opening table definitions file (" SPHERE_FILE "tables" SPHERE_SCRIPT_EXT ")...\n" ); return false; } - g_Log.Event(LOGL_EVENT|LOGM_INIT, "Loading table definitions file (" SPHERE_FILE "tables" SPHERE_SCRIPT ")...\n"); + g_Log.Event(LOGL_EVENT|LOGM_INIT, "Loading table definitions file (" SPHERE_FILE "tables" SPHERE_SCRIPT_EXT ")...\n"); LoadResourcesOpen(&m_scpTables); m_scpTables.Close(); } @@ -4991,7 +4991,7 @@ bool CServerConfig::DumpUnscriptedItems( CTextConsole * pSrc, lpctstr pszFilenam return false; if ( pszFilename == nullptr || pszFilename[0] == '\0' ) - pszFilename = "unscripted_items" SPHERE_SCRIPT; + pszFilename = "unscripted_items" SPHERE_SCRIPT_EXT; else if ( strlen( pszFilename ) <= 4 ) return false; diff --git a/src/game/CWorld.cpp b/src/game/CWorld.cpp index 05134381d..df69a4ad9 100644 --- a/src/game/CWorld.cpp +++ b/src/game/CWorld.cpp @@ -725,7 +725,7 @@ void CWorld::GetBackupName( CSString & sArchive, lpctstr pszBaseDir, tchar chTyp pszBaseDir, iGroup, iCount&0x07, chType, - SPHERE_SCRIPT ); + SPHERE_SCRIPT_EXT ); } bool CWorld::OpenScriptBackup( CScript & s, lpctstr pszBaseDir, lpctstr pszBaseName, int iSaveCount ) // static @@ -741,7 +741,7 @@ bool CWorld::OpenScriptBackup( CScript & s, lpctstr pszBaseDir, lpctstr pszBaseN // rename previous save to archive name. CSString sSaveName; - sSaveName.Format( "%s" SPHERE_FILE "%s%s", pszBaseDir, pszBaseName, SPHERE_SCRIPT ); + sSaveName.Format( "%s" SPHERE_FILE "%s%s", pszBaseDir, pszBaseName, SPHERE_SCRIPT_EXT ); if ( iSaveCount > 0 ) { if ( ::rename(sSaveName, sArchive) ) @@ -1098,7 +1098,7 @@ bool CWorld::CheckAvailableSpaceForSave(bool fStatics) auto CalcPrevSavesSize = [=, &fSizeErr, &uiPreviousSaveSize](lpctstr ptcSaveName) -> void { struct stat st; - CSString strSaveFile = g_Cfg.m_sWorldBaseDir + SPHERE_FILE + ptcSaveName + SPHERE_SCRIPT; + CSString strSaveFile = g_Cfg.m_sWorldBaseDir + SPHERE_FILE + ptcSaveName + SPHERE_SCRIPT_EXT; if (!stat(strSaveFile.GetBuffer(), &st)) { const ullong uiCurSavefileSize = (ullong)st.st_size; @@ -1357,19 +1357,19 @@ bool CWorld::LoadWorld() // Load world from script // NOTE: WE MUST Sync these files ! CHAR and WORLD !!! CSString sStaticsName; - sStaticsName.Format("%s" SPHERE_FILE "statics" SPHERE_SCRIPT, static_cast(g_Cfg.m_sWorldBaseDir)); + sStaticsName.Format("%s" SPHERE_FILE "statics" SPHERE_SCRIPT_EXT, static_cast(g_Cfg.m_sWorldBaseDir)); CSString sWorldName; - sWorldName.Format("%s" SPHERE_FILE "world" SPHERE_SCRIPT, static_cast(g_Cfg.m_sWorldBaseDir)); + sWorldName.Format("%s" SPHERE_FILE "world" SPHERE_SCRIPT_EXT, static_cast(g_Cfg.m_sWorldBaseDir)); CSString sMultisName; - sMultisName.Format("%s" SPHERE_FILE "multis" SPHERE_SCRIPT, static_cast(g_Cfg.m_sWorldBaseDir)); + sMultisName.Format("%s" SPHERE_FILE "multis" SPHERE_SCRIPT_EXT, static_cast(g_Cfg.m_sWorldBaseDir)); CSString sCharsName; - sCharsName.Format("%s" SPHERE_FILE "chars" SPHERE_SCRIPT, static_cast(g_Cfg.m_sWorldBaseDir)); + sCharsName.Format("%s" SPHERE_FILE "chars" SPHERE_SCRIPT_EXT, static_cast(g_Cfg.m_sWorldBaseDir)); CSString sDataName; - sDataName.Format("%s" SPHERE_FILE "data" SPHERE_SCRIPT, static_cast(g_Cfg.m_sWorldBaseDir)); + sDataName.Format("%s" SPHERE_FILE "data" SPHERE_SCRIPT_EXT, static_cast(g_Cfg.m_sWorldBaseDir)); int iPrevSaveCount = m_iSaveCountID; for (;;) diff --git a/src/game/CWorldImport.cpp b/src/game/CWorldImport.cpp index 693d4c9d4..98ee09c38 100644 --- a/src/game/CWorldImport.cpp +++ b/src/game/CWorldImport.cpp @@ -816,7 +816,7 @@ bool CWorld::Import( lpctstr pszFilename, const CChar * pSrc, word wModeFlags, i fImport.m_pszArg1 = pszArg1; fImport.m_pszArg2 = pszArg2; - if ( ! strcmpi( pszFilename + (iLen - 4), ".WSC" )) + if ( ! strcmpi( pszFilename + (iLen - 4), ".WSC" )) { if ( ! fImport.ImportWSC(s, wModeFlags, dx, dy )) return false; @@ -844,7 +844,7 @@ bool CWorld::DumpAreas( CTextConsole * pSrc, lpctstr pszFilename ) return false; if ( pszFilename == nullptr || *pszFilename == '\0' ) - pszFilename = "map_all" SPHERE_SCRIPT; + pszFilename = "map_all" SPHERE_SCRIPT_EXT; else if ( strlen( pszFilename ) <= 4 ) return false; diff --git a/src/game/chars/CCharAct.cpp b/src/game/chars/CCharAct.cpp index e8d4c8269..e07bd77c0 100644 --- a/src/game/chars/CCharAct.cpp +++ b/src/game/chars/CCharAct.cpp @@ -5929,12 +5929,12 @@ bool CChar::OnTickPeriodic() } else { -#ifdef _DEBUG +//#ifdef _DEBUG if (deathRes != DeathRequestResult::AbortedNoLog) { g_Log.EventEvent("Aborted char '%s' (0x%" PRIx32 " ) death.\n", GetName(), GetUID().GetObjUID()); } -#endif +//#endif ; // Then, fall through. } } diff --git a/src/game/clients/CAccount.cpp b/src/game/clients/CAccount.cpp index a7a82c695..4d4eca1b0 100644 --- a/src/game/clients/CAccount.cpp +++ b/src/game/clients/CAccount.cpp @@ -73,7 +73,7 @@ bool CAccounts::Account_LoadAll( bool fChanges, bool fClearChanges ) char *z = Str_GetTemp(); pszBaseDir = g_Cfg.m_sAcctBaseDir.IsEmpty() ? g_Cfg.m_sWorldBaseDir : g_Cfg.m_sAcctBaseDir; - pszBaseName = ( fChanges ) ? (SPHERE_FILE "acct" SPHERE_SCRIPT) : (SPHERE_FILE "accu" SPHERE_SCRIPT); + pszBaseName = ( fChanges ) ? (SPHERE_FILE "acct" SPHERE_SCRIPT_EXT) : (SPHERE_FILE "accu" SPHERE_SCRIPT_EXT); Str_CopyLimitNull(z, pszBaseDir, Str_TempLength()); Str_ConcatLimitNull(z, pszBaseName, Str_TempLength()); @@ -104,7 +104,7 @@ bool CAccounts::Account_LoadAll( bool fChanges, bool fClearChanges ) if (!s.Open(nullptr, OF_WRITE | OF_TEXT | OF_DEFAULTMODE)) return false; - s.WriteString( "// Accounts are periodically moved to the " SPHERE_FILE "accu" SPHERE_SCRIPT " file.\n" + s.WriteString( "// Accounts are periodically moved to the " SPHERE_FILE "accu" SPHERE_SCRIPT_EXT " file.\n" "// All account changes should be made here.\n" "// Use the /ACCOUNT UPDATE command to force accounts to update.\n" ); @@ -142,7 +142,7 @@ bool CAccounts::Account_SaveAll() s.Printf("// " SPHERE_TITLE " %s accounts file\n" "// NOTE: This file cannot be edited while the server is running.\n" - "// Any file changes must be made to " SPHERE_FILE "accu" SPHERE_SCRIPT ". This is read in at save time.\n", + "// Any file changes must be made to " SPHERE_FILE "accu" SPHERE_SCRIPT_EXT ". This is read in at save time.\n", g_Serv.GetName()); for ( size_t i = 0; i < m_Accounts.size(); ++i ) diff --git a/src/game/clients/CClientLog.cpp b/src/game/clients/CClientLog.cpp index f3a84daf8..784ee801d 100644 --- a/src/game/clients/CClientLog.cpp +++ b/src/game/clients/CClientLog.cpp @@ -748,7 +748,7 @@ bool CClient::OnRxWebPageRequest( byte * pRequest, size_t uiLen ) tchar * ppRequest[4]; int iQtyArgs = Str_ParseCmds(ppLines[0], ppRequest, ARRAY_COUNT(ppRequest), " "); - if (( iQtyArgs < 2 ) || ( strlen(ppRequest[1]) >= _MAX_PATH )) + if (( iQtyArgs < 2 ) || ( strlen(ppRequest[1]) >= SPHERE_MAX_PATH )) return false; if ( strchr(ppRequest[1], '\r') || strchr(ppRequest[1], 0x0c) ) @@ -829,7 +829,7 @@ bool CClient::OnRxWebPageRequest( byte * pRequest, size_t uiLen ) // Host: localhost:2593\r\n // \r\n - tchar szPageName[_MAX_PATH]; + tchar szPageName[SPHERE_MAX_PATH]; if ( !Str_GetBare( szPageName, Str_TrimWhitespace(ppRequest[1]), sizeof(szPageName), "!\"#$%&()*,:;<=>?[]^{|}-+'`" ) ) return false; diff --git a/src/game/clients/CClientMsg.cpp b/src/game/clients/CClientMsg.cpp index 978b5affe..d2e6f6611 100644 --- a/src/game/clients/CClientMsg.cpp +++ b/src/game/clients/CClientMsg.cpp @@ -2722,7 +2722,7 @@ void CClient::SendPacket( tchar * ptcKey ) while ( *ptcKey ) { if ( packet->getLength() > SCRIPT_MAX_LINE_LEN - 4 ) - { // we won't get here because this lenght is enforced in all scripts + { // we won't get here because this length is enforced in all scripts DEBUG_ERR(("SENDPACKET too big.\n")); delete packet; @@ -2734,7 +2734,7 @@ void CClient::SendPacket( tchar * ptcKey ) if ( toupper(*ptcKey) == 'D' ) { ++ptcKey; - dword iVal = Exp_GetVal(ptcKey); + dword iVal = Exp_GetDWVal(ptcKey); packet->writeInt32(iVal); } diff --git a/src/game/spheresvr.cpp b/src/game/spheresvr.cpp index be7f4c857..d56b7680a 100644 --- a/src/game/spheresvr.cpp +++ b/src/game/spheresvr.cpp @@ -71,7 +71,7 @@ GlobalInitializer::GlobalInitializer() //--- Exception handling -#ifdef WINDOWS_SEH_EXCEPTION_MODEL +#ifdef WINDOWS_SPHERE_SHOULD_HANDLE_STRUCTURED_EXCEPTIONS SetWindowsStructuredExceptionTranslator(); #endif diff --git a/src/sphere/ntservice.cpp b/src/sphere/ntservice.cpp index 0e0bdb707..6e05dd8bf 100644 --- a/src/sphere/ntservice.cpp +++ b/src/sphere/ntservice.cpp @@ -252,7 +252,7 @@ void CNTService::ServiceStop() // PURPOSE: Installs the service on the local machine void CNTService::CmdInstallService() { - char szPath[_MAX_PATH * 2]; + char szPath[SPHERE_MAX_PATH * 2]; char szErr[256]; ReportEvent(EVENTLOG_INFORMATION_TYPE, 0, "Installing Service."); diff --git a/src/sphere/ntwindow.cpp b/src/sphere/ntwindow.cpp index ce3a38b73..d5804aa4a 100644 --- a/src/sphere/ntwindow.cpp +++ b/src/sphere/ntwindow.cpp @@ -748,7 +748,7 @@ LRESULT CNTWindow::OnNotify( int idCtrl, NMHDR * pnmh ) break; // use dclick to open the corresponding script file - TCHAR * pos = strstr(zTemp, SPHERE_SCRIPT); + TCHAR * pos = strstr(zTemp, SPHERE_SCRIPT_EXT); if ( pos != nullptr ) { // use two formats of file names: @@ -784,7 +784,7 @@ LRESULT CNTWindow::OnNotify( int idCtrl, NMHDR * pnmh ) // since certain files aren't listed, handle these separately if (filePath == nullptr) { - if ( strstr(SPHERE_FILE "tables" SPHERE_SCRIPT, start) ) + if ( strstr(SPHERE_FILE "tables" SPHERE_SCRIPT_EXT, start) ) { TCHAR * z = Str_GetTemp(); strcpy(z, g_Cfg.m_sSCPBaseDir); diff --git a/src/sphere/threads.cpp b/src/sphere/threads.cpp index 7c9306885..23119d208 100644 --- a/src/sphere/threads.cpp +++ b/src/sphere/threads.cpp @@ -643,7 +643,7 @@ void AbstractThread::onStart() // when implemented in derived classes this method must always be called too, preferably before // the custom implementation -#ifdef WINDOWS_SEH_EXCEPTION_MODEL +#ifdef WINDOWS_SPHERE_SHOULD_HANDLE_STRUCTURED_EXCEPTIONS SetWindowsStructuredExceptionTranslator(); #endif From 8643b0bb8734be628d6a284f0baded6fce1a84bc Mon Sep 17 00:00:00 2001 From: cbnolok Date: Sat, 5 Oct 2024 18:44:40 +0200 Subject: [PATCH 24/32] More refactoring, removed some macros from os_unix.h, renamed to uppercase some macros, converted some strcpy to safer variants. --- src/common/CDataBase.cpp | 4 +-- src/common/CDataBase.h | 4 +-- src/common/CException.cpp | 26 ++++++++++--------- src/common/CLog.cpp | 6 ++--- src/common/CLog.h | 16 ++++++------ src/common/CRect.cpp | 2 -- src/common/CScript.cpp | 6 ++--- src/common/CScript.h | 4 +-- src/common/CTextConsole.cpp | 2 +- src/common/CTextConsole.h | 2 +- src/common/CUOClientVersion.cpp | 2 -- src/common/common.h | 6 ++--- src/common/crashdump/crashdump.cpp | 2 +- src/common/crashdump/crashdump.h | 2 +- src/common/os_unix.h | 30 ++++++++-------------- src/common/os_windows.h | 8 +++--- src/common/sphere_library/CSFile.cpp | 4 +-- src/common/sphere_library/CSFileText.cpp | 4 +-- src/common/sphere_library/CSFileText.h | 4 +-- src/common/sphere_library/CSString.cpp | 2 +- src/common/sphere_library/CSString.h | 2 +- src/common/sphere_library/CSTime.cpp | 3 +-- src/common/sphere_library/sresetevents.cpp | 4 +++ src/game/CBase.cpp | 6 ++--- src/game/CServerDef.cpp | 2 +- src/game/CWorldCache.cpp | 4 +-- src/game/CWorldComm.cpp | 2 +- src/game/CWorldComm.h | 2 +- src/game/clients/CClientDialog.cpp | 4 ++- src/game/clients/CClientTooltip.cpp | 2 +- src/game/clients/CClientTooltip.h | 2 +- src/game/spheresvr.cpp | 8 +++--- src/network/CNetState.cpp | 2 +- src/network/CSocket.cpp | 6 ++--- src/sphere/ProfileData.cpp | 2 +- src/sphere/ntservice.cpp | 2 +- src/sphere/threads.cpp | 4 --- 37 files changed, 92 insertions(+), 101 deletions(-) diff --git a/src/common/CDataBase.cpp b/src/common/CDataBase.cpp index 909ee56c8..352359d24 100644 --- a/src/common/CDataBase.cpp +++ b/src/common/CDataBase.cpp @@ -167,7 +167,7 @@ bool CDataBase::query(const char *query, CVarDefMap & mapQueryResult) return false; } -bool __cdecl CDataBase::queryf(CVarDefMap & mapQueryResult, char *fmt, ...) +bool CDataBase::queryf(CVarDefMap & mapQueryResult, char *fmt, ...) { ADDTOCALLSTACK("CDataBase::queryf"); TemporaryString tsBuf; @@ -214,7 +214,7 @@ bool CDataBase::exec(const char *query) return false; } -bool __cdecl CDataBase::execf(char *fmt, ...) +bool CDataBase::execf(char *fmt, ...) { ADDTOCALLSTACK("CDataBase::execf"); TemporaryString tsBuf; diff --git a/src/common/CDataBase.h b/src/common/CDataBase.h index ee084ae50..d166cd70d 100644 --- a/src/common/CDataBase.h +++ b/src/common/CDataBase.h @@ -37,9 +37,9 @@ class CDataBase : public CScriptObj // select bool query(const char *query, CVarDefMap & mapQueryResult); // proceeds the query for SELECT - bool __cdecl queryf(CVarDefMap & mapQueryResult, char *fmt, ...) __printfargs(3,4); + bool queryf(CVarDefMap & mapQueryResult, char *fmt, ...) SPHERE_PRINTFARGS(3,4); bool exec(const char *query); // executes query (pretty faster) for ALTER, UPDATE, INSERT, DELETE, ... - bool __cdecl execf(char *fmt, ...) __printfargs(2,3); + bool execf(char *fmt, ...) SPHERE_PRINTFARGS(2,3); void addQueryResult(CSString & theFunction, CScriptTriggerArgs * theResult); // set / get / info methods diff --git a/src/common/CException.cpp b/src/common/CException.cpp index 202463459..6b41a9db0 100644 --- a/src/common/CException.cpp +++ b/src/common/CException.cpp @@ -235,7 +235,7 @@ void Assert_Fail( lpctstr pExp, lpctstr pFile, long long llLine ) throw CAssert(LOGL_CRIT, pExp, pFile, llLine); } -static void _cdecl Sphere_Purecall_Handler() +static void SPHERE_CDECL Sphere_Purecall_Handler() { // catch this special type of C++ exception as well. Assert_Fail("purecall", "unknown", 1); @@ -244,6 +244,7 @@ static void _cdecl Sphere_Purecall_Handler() void SetPurecallHandler() { // We don't want sphere to immediately exit if something calls a pure virtual method. + // Those functions set the behavior process-wide, so there's no need to call this on each thread. #ifdef MSVC_COMPILER _set_purecall_handler(Sphere_Purecall_Handler); #else @@ -254,7 +255,7 @@ void SetPurecallHandler() } #ifdef WINDOWS_SPHERE_SHOULD_HANDLE_STRUCTURED_EXCEPTIONS -static void _cdecl Sphere_Structured_Exception_Windows( unsigned int id, struct _EXCEPTION_POINTERS* pData ) +static void SPHERE_CDECL Sphere_Structured_Exception_Windows( unsigned int id, struct _EXCEPTION_POINTERS* pData ) { # ifdef WINDOWS_SHOULD_EMIT_CRASH_DUMP if ( CrashDump::IsEnabled() ) @@ -272,17 +273,18 @@ static void _cdecl Sphere_Structured_Exception_Windows( unsigned int id, struct void SetWindowsStructuredExceptionTranslator() { + // Process-wide, no need to call this on each thread. _set_se_translator( Sphere_Structured_Exception_Windows ); } #endif #ifndef _WIN32 -static void _cdecl Signal_Hangup(int sig = 0) noexcept // If shutdown is initialized +static void Signal_Hangup(int sig = 0) noexcept // If shutdown is initialized { UnreferencedParameter(sig); #ifdef THREAD_TRACK_CALLSTACK - static bool _Signal_Hangup_stack_printed = false; + static thread_local bool _Signal_Hangup_stack_printed = false; if (!_Signal_Hangup_stack_printed) { StackDebugInformation::printStackTrace(); @@ -296,13 +298,13 @@ static void _cdecl Signal_Hangup(int sig = 0) noexcept // If shutdown is initial g_Serv.SetExitFlag(SIGHUP); } -static void _cdecl Signal_Terminate(int sig = 0) noexcept // If shutdown is initialized +static void Signal_Terminate(int sig = 0) noexcept // If shutdown is initialized { g_Log.Event(LOGL_FATAL, "Server Unstable: %s signal received\n", strsignal(sig)); #ifdef THREAD_TRACK_CALLSTACK - static bool _Signal_Terminate_stack_printed = false; + static thread_local bool _Signal_Terminate_stack_printed = false; if (!_Signal_Terminate_stack_printed) { StackDebugInformation::printStackTrace(); @@ -350,7 +352,7 @@ static void _cdecl Signal_Terminate(int sig = 0) noexcept // If shutdown is init //exit(EXIT_FAILURE); // Having set the exit flag, all threads "should" terminate cleanly. } -static void _cdecl Signal_Break(int sig = 0) // signal handler attached when using secure mode +static void Signal_Break(int sig = 0) // signal handler attached when using secure mode { // Shouldn't be needed, since gdb consumes the signals itself and this code won't be executed //#ifdef _DEBUG @@ -371,7 +373,7 @@ static void _cdecl Signal_Break(int sig = 0) // signal handler attached when us } } -static void _cdecl Signal_Illegal_Instruction(int sig = 0) +static void Signal_Illegal_Instruction(int sig = 0) { #ifdef THREAD_TRACK_CALLSTACK StackDebugInformation::freezeCallStack(true); @@ -398,7 +400,7 @@ static void _cdecl Signal_Illegal_Instruction(int sig = 0) throw CSError(LOGL_FATAL, sig, strsignal(sig)); } -static void _cdecl Signal_Children(int sig = 0) +static void Signal_Children(int sig = 0) { UnreferencedParameter(sig); while (waitpid((pid_t)(-1), nullptr, WNOHANG) > 0) {} @@ -410,15 +412,15 @@ void SetUnixSignals( bool fSet ) // Signal handlers are installed only in sec { #ifdef _SANITIZERS - const bool fSan = true; + constexpr bool fSan = true; #else - const bool fSan = false; + constexpr bool fSan = false; #endif #ifdef _DEBUG const bool fDebugger = IsDebuggerPresent(); #else - const bool fDebugger = false; + constexpr bool fDebugger = false; #endif if (!fDebugger && !fSan) diff --git a/src/common/CLog.cpp b/src/common/CLog.cpp index 926dde738..364dadae5 100644 --- a/src/common/CLog.cpp +++ b/src/common/CLog.cpp @@ -358,7 +358,7 @@ int CLog::EventStr( dword dwMask, lpctstr pszMsg, ConsoleTextColor iLogColor) no CSTime CLog::sm_prevCatchTick; -void _cdecl CLog::CatchEvent( const CSError * pErr, lpctstr pszCatchContext, ... ) +void CLog::CatchEvent( const CSError * pErr, lpctstr pszCatchContext, ... ) { CSTime timeCurrent = CSTime::GetCurrentTime(); if ( sm_prevCatchTick.GetTime() == timeCurrent.GetTime() ) // prevent message floods. @@ -392,7 +392,7 @@ void _cdecl CLog::CatchEvent( const CSError * pErr, lpctstr pszCatchContext, ... va_start(vargs, pszCatchContext); uiLen += vsnprintf(szMsg + uiLen, sizeof(szMsg) - uiLen, pszCatchContext, vargs); - uiLen += snprintf (szMsg + uiLen, sizeof(szMsg) - uiLen, "\n"); + /*uiLen += */ snprintf (szMsg + uiLen, sizeof(szMsg) - uiLen, "\n"); EventStr(eSeverity, szMsg); va_end(vargs); @@ -405,7 +405,7 @@ void _cdecl CLog::CatchEvent( const CSError * pErr, lpctstr pszCatchContext, ... sm_prevCatchTick = timeCurrent; } -void _cdecl CLog::CatchStdException(const std::exception * pExc, lpctstr pszCatchContext, ...) +void CLog::CatchStdException(const std::exception * pExc, lpctstr pszCatchContext, ...) { tchar szMsg[512]; diff --git a/src/common/CLog.h b/src/common/CLog.h index fbb650620..27a100d74 100644 --- a/src/common/CLog.h +++ b/src/common/CLog.h @@ -66,12 +66,12 @@ class CEventLog int VEvent(dword dwMask, lpctstr pszFormat, ConsoleTextColor iColor, va_list args) noexcept; public: - int _cdecl Event( dword dwMask, lpctstr pszFormat, ... ) noexcept __printfargs(3,4); - int _cdecl EventDebug(lpctstr pszFormat, ...) noexcept __printfargs(2,3); - int _cdecl EventError(lpctstr pszFormat, ...) noexcept __printfargs(2,3); - int _cdecl EventWarn(lpctstr pszFormat, ...) noexcept __printfargs(2,3); - int _cdecl EventCustom(ConsoleTextColor iColor, dword dwMask, lpctstr pszFormat, ...) noexcept __printfargs(4,5); - int _cdecl EventEvent( lpctstr pszFormat, ... ) noexcept __printfargs(2,3); + int Event( dword dwMask, lpctstr pszFormat, ... ) noexcept SPHERE_PRINTFARGS(3,4); + int EventDebug(lpctstr pszFormat, ...) noexcept SPHERE_PRINTFARGS(2,3); + int EventError(lpctstr pszFormat, ...) noexcept SPHERE_PRINTFARGS(2,3); + int EventWarn(lpctstr pszFormat, ...) noexcept SPHERE_PRINTFARGS(2,3); + int EventCustom(ConsoleTextColor iColor, dword dwMask, lpctstr pszFormat, ...) noexcept SPHERE_PRINTFARGS(4,5); + int EventEvent( lpctstr pszFormat, ... ) noexcept SPHERE_PRINTFARGS(2,3); CEventLog(); virtual ~CEventLog(); @@ -119,8 +119,8 @@ public: bool OpenLog(lpctstr pszName = nullptr); bool IsLogged( dword dwMask ) const; virtual int EventStr( dword dwMask, lpctstr pszMsg, ConsoleTextColor iLogColor = CTCOL_DEFAULT ) noexcept final; // final: for now, it doesn't have any other virtual methods - void _cdecl CatchEvent( const CSError * pErr, lpctstr pszCatchContext, ... ) __printfargs(3,4); - void _cdecl CatchStdException( const std::exception * pExc, lpctstr pszCatchContext, ... ) __printfargs(3,4); + void CatchEvent( const CSError * pErr, lpctstr pszCatchContext, ... ) SPHERE_PRINTFARGS(3,4); + void CatchStdException( const std::exception * pExc, lpctstr pszCatchContext, ... ) SPHERE_PRINTFARGS(3,4); public: CLog(); diff --git a/src/common/CRect.cpp b/src/common/CRect.cpp index c25aea5a0..589fe09ac 100644 --- a/src/common/CRect.cpp +++ b/src/common/CRect.cpp @@ -1,7 +1,5 @@ #include "../game/uo_files/CUOMapList.h" #include "../game/CSectorList.h" -#include "../game/CServer.h" -#include "../game/CWorldMap.h" #include "CLog.h" #include "CRect.h" diff --git a/src/common/CScript.cpp b/src/common/CScript.cpp index 352bc1680..c7a4da969 100644 --- a/src/common/CScript.cpp +++ b/src/common/CScript.cpp @@ -841,7 +841,7 @@ CScriptLineContext CScript::GetContext() const return LineContext; } -bool _cdecl CScript::WriteSection( lpctstr ptcSection, ... ) +bool CScript::WriteSection( lpctstr ptcSection, ... ) { ADDTOCALLSTACK_DEBUG("CScript::WriteSection"); // Write out the section header. @@ -933,7 +933,7 @@ bool CScript::WriteKeyStr(lpctstr ptcKey, lpctstr ptcVal) return true; } -//void _cdecl CScript::WriteKeyFormat( lpctstr ptcKey, lpctstr pszVal, ... ) +//void CScript::WriteKeyFormat( lpctstr ptcKey, lpctstr pszVal, ... ) //{ // ADDTOCALLSTACK("CScript::WriteKeyFormat"); // tchar *pszTemp = Str_GetTemp(); @@ -945,7 +945,7 @@ bool CScript::WriteKeyStr(lpctstr ptcKey, lpctstr ptcVal) //} static thread_local tchar ptcWriteKeyBuf[SCRIPT_MAX_LINE_LEN]; -void _cdecl CScript::WriteKeyFormat(lpctstr ptcKey, lpctstr pszVal, ...) +void CScript::WriteKeyFormat(lpctstr ptcKey, lpctstr pszVal, ...) { ADDTOCALLSTACK_DEBUG("CScript::WriteKeyFormat"); va_list vargs; diff --git a/src/common/CScript.h b/src/common/CScript.h index 605f6156d..bb21601a0 100644 --- a/src/common/CScript.h +++ b/src/common/CScript.h @@ -159,8 +159,8 @@ public: CScriptLineContext GetContext() const; bool ReadKeyParse(); // Write stuff out to a script file. - bool _cdecl WriteSection(lpctstr pszSection, ...) __printfargs(2,3); - void _cdecl WriteKeyFormat(lpctstr ptcKey, lpctstr pszFormat, ...) __printfargs(3,4); + bool WriteSection(lpctstr pszSection, ...) SPHERE_PRINTFARGS(2,3); + void WriteKeyFormat(lpctstr ptcKey, lpctstr pszFormat, ...) SPHERE_PRINTFARGS(3,4); bool WriteKeySingle(lptstr ptcKey); bool WriteKeyStr(lpctstr ptcKey, lpctstr ptcVal); diff --git a/src/common/CTextConsole.cpp b/src/common/CTextConsole.cpp index b98c301e6..89fdbbf8b 100644 --- a/src/common/CTextConsole.cpp +++ b/src/common/CTextConsole.cpp @@ -139,7 +139,7 @@ void CTextConsole::VSysMessage( lpctstr pszFormat, va_list args ) const SysMessage(tsTemp.buffer()); } -void _cdecl CTextConsole::SysMessagef( lpctstr pszFormat, ... ) const +void CTextConsole::SysMessagef( lpctstr pszFormat, ... ) const { va_list vargs; va_start( vargs, pszFormat ); diff --git a/src/common/CTextConsole.h b/src/common/CTextConsole.h index 5429f4f85..4bd15f897 100644 --- a/src/common/CTextConsole.h +++ b/src/common/CTextConsole.h @@ -41,7 +41,7 @@ class CTextConsole virtual void SysMessage( lpctstr pszMessage ) const = 0; // Feed back message. void VSysMessage( lpctstr pszFormat, va_list args ) const; - void _cdecl SysMessagef( lpctstr pszFormat, ... ) const __printfargs(2,3); + void SysMessagef( lpctstr pszFormat, ... ) const SPHERE_PRINTFARGS(2,3); public: CTextConsole() { }; diff --git a/src/common/CUOClientVersion.cpp b/src/common/CUOClientVersion.cpp index 07113de19..56be65445 100644 --- a/src/common/CUOClientVersion.cpp +++ b/src/common/CUOClientVersion.cpp @@ -1,7 +1,5 @@ #include "CUOClientVersion.h" -#include "CExpression.h" #include "CLog.h" -#include "sphereproto.h" #include #include #include diff --git a/src/common/common.h b/src/common/common.h index deb52d81e..9932c6fd5 100644 --- a/src/common/common.h +++ b/src/common/common.h @@ -214,13 +214,13 @@ constexpr void UnreferencedParameter(T const&) noexcept { // (note: add 1 to index for non-static class methods because 'this' argument // is inserted in position 1) #ifdef MSVC_COMPILER - #define __printfargs(a,b) + #define SPHERE_PRINTFARGS(a,b) #else #ifdef __MINGW32__ // Clang doesn't have a way to switch from gnu or ms style printf arguments. It just depends on the runtime used. - #define __printfargs(a,b) __attribute__ ((format(gnu_printf, a, b))) + #define SPHERE_PRINTFARGS(a,b) __attribute__ ((format(gnu_printf, a, b))) #else - #define __printfargs(a,b) __attribute__ ((format(printf, a, b))) + #define SPHERE_PRINTFARGS(a,b) __attribute__ ((format(printf, a, b))) #endif #endif diff --git a/src/common/crashdump/crashdump.cpp b/src/common/crashdump/crashdump.cpp index 5f78264f2..3beb4ca5a 100644 --- a/src/common/crashdump/crashdump.cpp +++ b/src/common/crashdump/crashdump.cpp @@ -1,4 +1,4 @@ -#if defined(_WIN32) && !defined(_DEBUG) && !defined(_NO_CRASHDUMP) +#ifdef WINDOWS_SHOULD_EMIT_CRASH_DUMP #include "crashdump.h" diff --git a/src/common/crashdump/crashdump.h b/src/common/crashdump/crashdump.h index 0a8387722..5de0b33ef 100644 --- a/src/common/crashdump/crashdump.h +++ b/src/common/crashdump/crashdump.h @@ -1,4 +1,4 @@ -#if !defined(_INC_CRASHDUMP_H) && defined(_WIN32) && !defined(_DEBUG) && !defined(_NO_CRASHDUMP) +#ifdef WINDOWS_SHOULD_EMIT_CRASH_DUMP #define _INC_CRASHDUMP_H #include diff --git a/src/common/os_unix.h b/src/common/os_unix.h index 492ce9cd7..92eee09b3 100644 --- a/src/common/os_unix.h +++ b/src/common/os_unix.h @@ -6,7 +6,7 @@ #ifndef _INC_OS_UNIX_H #define _INC_OS_UNIX_H -//#include // PATH_MAX +//#include // PATH_MAX #include // usleep #include // toupper, tolower @@ -33,9 +33,8 @@ // TODO: enable longer MAX_PATHs on both Linux and Windows, also checking that increasing that limit doesn't cause any buffer overflow. #define SPHERE_MAX_PATH 260 -#define _cdecl -#define __cdecl -#define FAR +//#define SPHERE_CDECL __attribute__((cdecl)) +#define SPHERE_CDECL #define E_FAIL 0x80004005 // exception code @@ -47,17 +46,14 @@ #define HIWORD(l) ((word)((dword)(l) >> 16)) #define LOBYTE(w) ((byte)((dword)(w) & 0xff)) #define HIBYTE(w) ((byte)((dword)(w) >> 8)) -#define IsBadReadPtr( p, len ) ((p) == nullptr) -#define IsBadStringPtr( p, len ) ((p) == nullptr) -#define Sleep(mSec) usleep(mSec*1000) // arg is microseconds = 1/1000000 -#define SleepEx(mSec, unused) usleep(mSec*1000) // arg is microseconds = 1/1000000 #ifdef _BSD int getTimezone(); - #define _timezone getTimezone() + #define TIMEZONE getTimezone() #else - #define _timezone timezone + #define TIMEZONE timezone #endif + /* */ /* file handling definitions */ @@ -70,24 +66,18 @@ /* thread-specific definitions */ #define STDFUNC_GETPID getpid #define CRITICAL_SECTION pthread_mutex_t -#define Sleep(mSec) usleep(mSec*1000) // arg is microseconds = 1/1000000 -#define SleepEx(mSec, unused) usleep(mSec*1000) // arg is microseconds = 1/1000000 -/* */ - -#define ERROR_SUCCESS 0 -#define HKEY_LOCAL_MACHINE (( HKEY ) 0x80000002 ) +/* */ +#define SLEEP(mSec) usleep(mSec*1000) // arg is microseconds = 1/1000000 /* No portable UNIX/LINUX equiv to this. */ - -// The others, not inlined, are in common.cpp -inline void _strupr( tchar * pszStr ) +inline void _strupr( tchar * pszStr ) noexcept { for ( ; pszStr[0] != '\0'; ++pszStr ) *pszStr = toupper( *pszStr ); } -inline void _strlwr( tchar * pszStr ) +inline void _strlwr( tchar * pszStr ) noexcept { for ( ; pszStr[0] != '\0'; ++pszStr ) *pszStr = tolower( *pszStr ); diff --git a/src/common/os_windows.h b/src/common/os_windows.h index 13e39d1b5..c2c9f91cf 100644 --- a/src/common/os_windows.h +++ b/src/common/os_windows.h @@ -71,6 +71,7 @@ # pragma warning(pop) #endif +#define SPHERE_CDECL __cdecl /* file handling definitions */ #define STDFUNC_FILENO(_x_) _get_osfhandle(_fileno(_x_)) @@ -89,15 +90,16 @@ #endif #ifdef __MINGW32__ // No Microsoft compiler - #define _cdecl __cdecl - // Not defined for mingw. #define LSTATUS int - typedef void (__cdecl *_invalid_parameter_handler)(const wchar_t *,const wchar_t *,const wchar_t *,unsigned int,uintptr_t); + typedef void (SPHERE_CDECL *_invalid_parameter_handler)(const wchar_t *,const wchar_t *,const wchar_t *,unsigned int,uintptr_t); // Stuctured exception handling windows api not implemented on mingw. #define __except(P) catch(int) #endif // _MSC_VER +#define SLEEP Sleep +#define TIMEZONE _timezone + const OSVERSIONINFO * Sphere_GetOSInfo() noexcept; diff --git a/src/common/sphere_library/CSFile.cpp b/src/common/sphere_library/CSFile.cpp index 42d3bf124..513bf8793 100644 --- a/src/common/sphere_library/CSFile.cpp +++ b/src/common/sphere_library/CSFile.cpp @@ -442,9 +442,9 @@ CSString CSFile::GetMergedFileName( lpctstr pszBase, lpctstr pszName ) // static if (len && ptcFilePath[len - 1] != '\\' && ptcFilePath[len - 1] != '/') { #ifdef _WIN32 - strcat(ptcFilePath, "\\"); + ptcFilePath[len] = '\\'; #else - strcat(ptcFilePath, "/"); + ptcFilePath[len] = '/'; #endif } } diff --git a/src/common/sphere_library/CSFileText.cpp b/src/common/sphere_library/CSFileText.cpp index 686437c9f..adbfb8be4 100644 --- a/src/common/sphere_library/CSFileText.cpp +++ b/src/common/sphere_library/CSFileText.cpp @@ -155,7 +155,7 @@ bool CSFileText::IsEOF() const } -int _cdecl CSFileText::_Printf(lpctstr pFormat, ...) +int CSFileText::_Printf(lpctstr pFormat, ...) { ADDTOCALLSTACK("CSFileText::_Printf"); ASSERT(pFormat); @@ -167,7 +167,7 @@ int _cdecl CSFileText::_Printf(lpctstr pFormat, ...) return iRet; } -int _cdecl CSFileText::Printf( lpctstr pFormat, ... ) +int CSFileText::Printf( lpctstr pFormat, ... ) { ADDTOCALLSTACK("CSFileText::Printf"); ASSERT(pFormat); diff --git a/src/common/sphere_library/CSFileText.h b/src/common/sphere_library/CSFileText.h index f8912cad7..8727491b4 100644 --- a/src/common/sphere_library/CSFileText.h +++ b/src/common/sphere_library/CSFileText.h @@ -84,8 +84,8 @@ public: virtual bool IsEOF() const; * @param ... argument list. * @return total chars of the output. */ -protected: int _cdecl _Printf( lpctstr pFormat, ... ) __printfargs(2,3); -public: int _cdecl Printf(lpctstr pFormat, ...) __printfargs(2, 3); +protected: int _Printf( lpctstr pFormat, ... ) SPHERE_PRINTFARGS(2,3); +public: int Printf(lpctstr pFormat, ...) SPHERE_PRINTFARGS(2, 3); /** * @brief Reads data from the file. * @param pBuffer buffer where store the readed data. diff --git a/src/common/sphere_library/CSString.cpp b/src/common/sphere_library/CSString.cpp index fdd3db4c9..a0cc3b665 100644 --- a/src/common/sphere_library/CSString.cpp +++ b/src/common/sphere_library/CSString.cpp @@ -261,7 +261,7 @@ CSString& CSString::operator=(CSString&& s) noexcept // CSString:: Formatting -void _cdecl CSString::Format(lpctstr pStr, ...) +void CSString::Format(lpctstr pStr, ...) { va_list vargs; va_start(vargs, pStr); diff --git a/src/common/sphere_library/CSString.h b/src/common/sphere_library/CSString.h index ce0949e0a..26aedb428 100644 --- a/src/common/sphere_library/CSString.h +++ b/src/common/sphere_library/CSString.h @@ -307,7 +307,7 @@ class CSString * @param pStr formatted string. * @param ... list of values. */ - void _cdecl Format(lpctstr pStr, ...) __printfargs(2, 3); + void Format(lpctstr pStr, ...) SPHERE_PRINTFARGS(2, 3); /** * @brief Join a formated string (printf like) with values and copy into this. diff --git a/src/common/sphere_library/CSTime.cpp b/src/common/sphere_library/CSTime.cpp index 45d3ac118..7985f29a4 100644 --- a/src/common/sphere_library/CSTime.cpp +++ b/src/common/sphere_library/CSTime.cpp @@ -5,7 +5,6 @@ // #include "../../sphere/threads.h" -#include "../CLog.h" #include "sstring.h" #include "CSTime.h" #include @@ -257,7 +256,7 @@ std::tm CSTime::GetLocalTmPlain() const noexcept #endif #if defined(_WIN32) && defined (MSVC_COMPILER) -static void __cdecl invalidParameterHandler(const wchar_t* expression, const wchar_t* function, const wchar_t* file, uint line, uintptr_t pReserved) +static void SPHERE_CDECL invalidParameterHandler(const wchar_t* expression, const wchar_t* function, const wchar_t* file, uint line, uintptr_t pReserved) { // bad format has been specified UnreferencedParameter(expression); diff --git a/src/common/sphere_library/sresetevents.cpp b/src/common/sphere_library/sresetevents.cpp index aaa245093..bc4d875c3 100644 --- a/src/common/sphere_library/sresetevents.cpp +++ b/src/common/sphere_library/sresetevents.cpp @@ -39,7 +39,11 @@ void AutoResetEvent::wait(uint timeout) // if timeout is 0 then the thread's timeslice may not be given up as with normal // sleep methods - so we will check for this condition ourselves and use SleepEx // instead +#ifdef _WIN32 SleepEx(0, TRUE); +#else + SLEEP(0); +#endif return; } diff --git a/src/game/CBase.cpp b/src/game/CBase.cpp index cd0311d11..52773a54e 100644 --- a/src/game/CBase.cpp +++ b/src/game/CBase.cpp @@ -235,9 +235,9 @@ bool CBaseBaseDef::r_WriteVal( lpctstr ptcKey, CSString & sVal, CTextConsole * p tchar *pszTmp = Str_GetTemp(); m_BaseResources.WriteKeys( pszTmp, Str_TempLength(), index, fQtyOnly, fKeyOnly ); if ( fQtyOnly && pszTmp[0] == '\0' ) - strcpy( pszTmp, "0" ); - - sVal = pszTmp; + sVal.SetValFalse(); // '0' + else + sVal = pszTmp; } } else diff --git a/src/game/CServerDef.cpp b/src/game/CServerDef.cpp index 063600ca4..ec84ff743 100644 --- a/src/game/CServerDef.cpp +++ b/src/game/CServerDef.cpp @@ -54,7 +54,7 @@ CServerDef::CServerDef( lpctstr pszName, CSocketAddressIP dwIP ) : _iTimeCreate = CWorldGameTime::GetCurrentTime().GetTimeRaw(); // Set default time zone from UTC - m_TimeZone = (char)( _timezone / (60 * 60) ); // Greenwich mean time. + m_TimeZone = (char)( TIMEZONE / (60 * 60) ); // Greenwich mean time. m_eAccApp = ACCAPP_Unspecified; } diff --git a/src/game/CWorldCache.cpp b/src/game/CWorldCache.cpp index a5f3459b4..6873ee560 100644 --- a/src/game/CWorldCache.cpp +++ b/src/game/CWorldCache.cpp @@ -3,6 +3,7 @@ #include "uo_files/CUOMapList.h" #include "CWorldCache.h" + CWorldCache::CWorldCache() { _iTimeLastMapBlockCacheCheck = 0; @@ -11,8 +12,7 @@ CWorldCache::CWorldCache() _mapBlocks[i].reset(); } - -static int _GetMapBlocksCount(int iMap) +static int _GetMapBlocksCount(int iMap) noexcept { const int iXBlocks = g_MapList.GetMapSizeX(iMap) / UO_BLOCK_SIZE; const int iYBlocks = g_MapList.GetMapSizeY(iMap) / UO_BLOCK_SIZE; diff --git a/src/game/CWorldComm.cpp b/src/game/CWorldComm.cpp index d7d3f56a8..78713a5ca 100644 --- a/src/game/CWorldComm.cpp +++ b/src/game/CWorldComm.cpp @@ -235,7 +235,7 @@ void CWorldComm::Broadcast(lpctstr pMsg) // static Speak( nullptr, pMsg, HUE_TEXT_DEF, TALKMODE_BROADCAST, FONT_BOLD ); } -void __cdecl CWorldComm::Broadcastf(lpctstr pMsg, ...) // static +void CWorldComm::Broadcastf(lpctstr pMsg, ...) // static { // System broadcast in bold text ADDTOCALLSTACK("CWorldComm::Broadcastf"); diff --git a/src/game/CWorldComm.h b/src/game/CWorldComm.h index 065d101b7..6a365c54b 100644 --- a/src/game/CWorldComm.h +++ b/src/game/CWorldComm.h @@ -24,7 +24,7 @@ class CWorldComm static void SpeakUNICODE(const CObjBaseTemplate* pSrc, const nachar* pText, HUE_TYPE wHue, TALKMODE_TYPE mode, FONT_TYPE font, CLanguageID lang); static void Broadcast(lpctstr pMsg); - static void __cdecl Broadcastf(lpctstr pMsg, ...) __printfargs(1, 2); + static void Broadcastf(lpctstr pMsg, ...) SPHERE_PRINTFARGS(1, 2); }; diff --git a/src/game/clients/CClientDialog.cpp b/src/game/clients/CClientDialog.cpp index d75c49988..a7fd691ed 100644 --- a/src/game/clients/CClientDialog.cpp +++ b/src/game/clients/CClientDialog.cpp @@ -125,7 +125,9 @@ bool CClient::addGumpDialogProps( const CUID& uid ) addSkillWindow((SKILL_TYPE)(g_Cfg.m_iMaxSkill), true); tchar *pszMsg = Str_GetTemp(); - strcpy(pszMsg, pObj->IsItem() ? "D_ITEMPROP1" : "D_CHARPROP1" ); + Str_CopyLimitNull(pszMsg, + (pObj->IsItem() ? "D_ITEMPROP1" : "D_CHARPROP1"), + Str_TempLength()); CResourceID rid = g_Cfg.ResourceGetIDType(RES_DIALOG, pszMsg); if ( ! rid.IsValidUID()) diff --git a/src/game/clients/CClientTooltip.cpp b/src/game/clients/CClientTooltip.cpp index 036865271..5f72b3ffa 100644 --- a/src/game/clients/CClientTooltip.cpp +++ b/src/game/clients/CClientTooltip.cpp @@ -21,7 +21,7 @@ CClientTooltip::CClientTooltip(dword dwClilocID, int64 iArgs) snprintf(m_args, MAX_TOOLTIP_LEN - 1, "%" PRId64, iArgs); } -void __cdecl CClientTooltip::FormatArgs(lpctstr format, ...) +void CClientTooltip::FormatArgs(lpctstr format, ...) { va_list vargs; va_start( vargs, format ); diff --git a/src/game/clients/CClientTooltip.h b/src/game/clients/CClientTooltip.h index 350e02ada..0375961ab 100644 --- a/src/game/clients/CClientTooltip.h +++ b/src/game/clients/CClientTooltip.h @@ -28,7 +28,7 @@ class CClientTooltip CClientTooltip& operator=(const CClientTooltip& other) = delete; public: - void __cdecl FormatArgs(lpctstr format, ...) __printfargs(2,3); + void FormatArgs(lpctstr format, ...) SPHERE_PRINTFARGS(2,3); }; diff --git a/src/game/spheresvr.cpp b/src/game/spheresvr.cpp index d56b7680a..12708dc69 100644 --- a/src/game/spheresvr.cpp +++ b/src/game/spheresvr.cpp @@ -444,7 +444,7 @@ static void Sphere_MainMonitorLoop() if ( g_Serv.GetExitFlag() ) break; - Sleep(1000); + SLEEP(1000); } EXC_SET_BLOCK("Checks"); @@ -472,13 +472,13 @@ void atexit_handler() #ifdef _WIN32 int Sphere_MainEntryPoint( int argc, char *argv[] ) #else -int _cdecl main( int argc, char * argv[] ) +int main( int argc, char * argv[] ) #endif { static constexpr lpctstr m_sClassName = "main"; EXC_TRY("MAIN"); - const int atexit_handler_result = std::atexit(atexit_handler); // Handler will be called + const int atexit_handler_result = std::atexit(atexit_handler); // Handler will be called if (atexit_handler_result != 0) { g_Log.Event(LOGL_CRIT, "atexit handler registration failed.\n"); @@ -547,7 +547,7 @@ int _cdecl main( int argc, char * argv[] ) { while (g_NTWindow.isActive()) { - Sleep (100); + SLEEP(100); } } #endif diff --git a/src/network/CNetState.cpp b/src/network/CNetState.cpp index ae3ecc506..8623ed7c7 100644 --- a/src/network/CNetState.cpp +++ b/src/network/CNetState.cpp @@ -55,7 +55,7 @@ void CNetState::clear(void) g_Serv.StatDec(SERV_STAT_CLIENTS); const CONNECT_TYPE connectionType = m_client->GetConnectType(); - const LOG_TYPE logFlags = LOG_TYPE(LOGM_NOCONTEXT | LOGM_CLIENTS_LOG | LOGL_EVENT); + const LOG_TYPE logFlags = enum_alias_cast(LOGM_NOCONTEXT | LOGM_CLIENTS_LOG | LOGL_EVENT); const size_t uiClients = g_Serv.StatGet(SERV_STAT_CLIENTS); const lpctstr ptcAddress = m_peerAddress.GetAddrStr(); if (connectionType == CONNECT_LOGIN) diff --git a/src/network/CSocket.cpp b/src/network/CSocket.cpp index c99c40b05..9014f36bc 100644 --- a/src/network/CSocket.cpp +++ b/src/network/CSocket.cpp @@ -433,12 +433,12 @@ CSocketAddress CSocket::GetPeerName( ) const int CSocket::SetSockOpt( int nOptionName, const void * optval, int optlen, int nLevel ) const { // level = SOL_SOCKET and IPPROTO_TCP. - return( setsockopt( m_hSocket, nLevel, nOptionName, reinterpret_cast(optval), optlen )); + return( setsockopt( m_hSocket, nLevel, nOptionName, reinterpret_cast(optval), optlen )); } int CSocket::GetSockOpt( int nOptionName, void * optval, int * poptlen, int nLevel ) const { - return( getsockopt( m_hSocket, nLevel, nOptionName, reinterpret_cast(optval), reinterpret_cast(poptlen))); + return( getsockopt( m_hSocket, nLevel, nOptionName, reinterpret_cast(optval), reinterpret_cast(poptlen))); } #ifdef _WIN32 @@ -457,7 +457,7 @@ int CSocket::GetSockOpt( int nOptionName, void * optval, int * poptlen, int nLev { // TO BE CALLED IN CClient destructor !!! CancelIo(reinterpret_cast(m_hSocket)); - SleepEx(1, TRUE); + SleepEx(1, TRUE); } #else diff --git a/src/sphere/ProfileData.cpp b/src/sphere/ProfileData.cpp index 9789a3334..f57a17358 100644 --- a/src/sphere/ProfileData.cpp +++ b/src/sphere/ProfileData.cpp @@ -1,5 +1,5 @@ -#include "../common/sphere_library/CSTime.h" +//#include "../common/sphere_library/CSTime.h" #include "../game/CScriptProfiler.h" #include "ProfileData.h" #include "threads.h" diff --git a/src/sphere/ntservice.cpp b/src/sphere/ntservice.cpp index 6e05dd8bf..f1b643d02 100644 --- a/src/sphere/ntservice.cpp +++ b/src/sphere/ntservice.cpp @@ -408,7 +408,7 @@ void CNTService::CmdRemoveService() while ( QueryServiceStatus(schService, &m_sStatus) ) // wait the service to stop { if ( m_sStatus.dwCurrentState == SERVICE_STOP_PENDING ) - Sleep(1000); + SLEEP(1000); else break; } diff --git a/src/sphere/threads.cpp b/src/sphere/threads.cpp index 23119d208..9eb3d26f6 100644 --- a/src/sphere/threads.cpp +++ b/src/sphere/threads.cpp @@ -643,10 +643,6 @@ void AbstractThread::onStart() // when implemented in derived classes this method must always be called too, preferably before // the custom implementation -#ifdef WINDOWS_SPHERE_SHOULD_HANDLE_STRUCTURED_EXCEPTIONS - SetWindowsStructuredExceptionTranslator(); -#endif - // we set the id here to ensure it is available before the first tick, otherwise there's // a small delay when setting it from AbstractThread::start and it's possible for the id // to not be set fast enough (particular when using pthreads) From e194ba7dafc56528b423fc2f1966c754be9f4f3a Mon Sep 17 00:00:00 2001 From: cbnolok Date: Mon, 7 Oct 2024 15:06:47 +0200 Subject: [PATCH 25/32] Fixed path concat regression and fixed come cmake options being loaded before being set. --- CMakeLists.txt | 101 +++++++++--------- cmake/toolchains/Windows-MSVC.cmake | 42 +++++--- .../include/Windows-Clang_common.inc.cmake | 6 +- .../include/Windows-GNU_common.inc.cmake | 2 +- src/common/CException.h | 6 +- src/common/crashdump/crashdump.h | 2 + src/common/sphere_library/CSFile.cpp | 7 +- src/game/CServer.cpp | 2 +- src/game/spheresvr.cpp | 8 +- src/sphere/threads.cpp | 4 +- 10 files changed, 104 insertions(+), 76 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 491c597a2..445f0334b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,47 +3,6 @@ cmake_minimum_required(VERSION 3.24) set(CMAKE_SUPPRESS_REGENERATION TRUE) # Supress the ZERO_CHECK generation -# -------------------- GUI checkboxes -------------------- -if(NOT MSVC) - set (CMAKE_BUILD_TYPE "Nightly" CACHE STRING "Which build type to build? Expected values: Debug, Nightly or Release.") -endif() - -option( - CMAKE_NO_GIT_REVISION - "Do not try to retrieve the current git revision. Useful for building source not git-cloned from Github." - FALSE -) -option(CROSSCOMPILE "Are we compiling for a different target architecture?" FALSE) -option( - RUNTIME_STATIC_LINK - "Statically link inside the executable the runtime libraries? (MSVC, libc/libcc, libstdc++)." - FALSE -) -option(CMAKE_EXPORT_COMPILE_COMMANDS "Export compiler commands to compile_commands.json" TRUE) - -set(predef_LIB_LIBEV_BUILD FALSE) -if(NOT WIN32) - set(predef_LIB_LIBEV_BUILD TRUE) -endif() -option(LIB_LIBEV_BUILD "Build libev." ${predef_LIB_LIBEV_BUILD}) -option(LIB_SQLITE_BUILD "Build sqlite." TRUE) -option(LIB_ZLIB_BUILD "Build zlib." TRUE) - -if(WIN32) - option(WIN32_SPAWN_CONSOLE "Spawn an additional console, useful for debugging." FALSE) -endif() - -option(USE_COMPILER_HARDENING_OPTIONS "Enable compiler (even runtime) safety checks and code hardening." FALSE) -option(USE_ASAN "Enable AddressSanitizer." FALSE) -option(USE_UBSAN "Enable Undefined Behavior Sanitizer." FALSE) -option(USE_LSAN "Enable LeakSanitizer." FALSE) -option(USE_MSAN "Enable MemorySanitizer." FALSE) - -set(ENABLED_SANITIZER CACHE INTERNAL BOOL FALSE) -if(USE_ASAN OR USE_MSAN OR USE_LSAN OR USE_MSAN) - set(ENABLED_SANITIZER TRUE) -endif() - # -------------------- Utility functions -------------------- function(booleanize_str_find VAR) @@ -63,9 +22,14 @@ if((NOT TOOLCHAIN_LOADED) AND (NOT ${CMAKE_TOOLCHAIN_FILE} STREQUAL "")) endif() message(STATUS "Scanning system build tools...") - project(SphereServer CXX C) # does a scan for C++ and C compilers +# If we have not specified a toolchain, let's detect which one we should use, using the detected arch. +# We need to do this after "project", otherwise CMake doesn't know where it's running. +if(NOT TOOLCHAIN_LOADED) + include("cmake/DetectDefaultToolchain.cmake") +endif() + # Setup global flags, to be done before creating targets. if(NOT DEFINED CMAKE_CXX_STANDARD) @@ -109,16 +73,57 @@ set(CMAKE_EXE_LINKER_FLAGS_RELEASE "") # Also, it fails to create those predefined flags, which it needs, for custom build types (e.g. Nightly). set(CMAKE_EXE_LINKER_FLAGS_NIGHTLY "") +# -------------------- GUI checkboxes -------------------- + +option( + CMAKE_NO_GIT_REVISION + "Do not try to retrieve the current git revision. Useful for building source not git-cloned from Github." + FALSE +) +option(CROSSCOMPILE "Are we compiling for a different target architecture?" FALSE) +option( + RUNTIME_STATIC_LINK + "Statically link inside the executable the runtime libraries? (MSVC, libc/libcc, libstdc++)." + FALSE +) +option(CMAKE_EXPORT_COMPILE_COMMANDS "Export compiler commands to compile_commands.json" TRUE) + +set(predef_LIB_LIBEV_BUILD FALSE) +if(NOT WIN32) + set(predef_LIB_LIBEV_BUILD TRUE) +endif() +option(LIB_LIBEV_BUILD "Build libev." ${predef_LIB_LIBEV_BUILD}) +option(LIB_SQLITE_BUILD "Build sqlite." TRUE) +option(LIB_ZLIB_BUILD "Build zlib." TRUE) + +if(WIN32) + option(WIN_SPAWN_CONSOLE "Spawn an additional console, useful for debugging." FALSE) + if(MSVC) + option(WIN_GENERATE_CRASHDUMP "For non-Debug builds, add Windows Structured Exception Handling and generate a Crash Dump if a fatal SE is thrown." FALSE) + endif() +endif() + +if(NOT MSVC) + option(USE_COMPILER_HARDENING_OPTIONS "Enable compiler (even runtime) safety checks and code hardening." FALSE) +endif() +option(USE_ASAN "Enable AddressSanitizer." FALSE) +option(USE_UBSAN "Enable Undefined Behavior Sanitizer." FALSE) +option(USE_LSAN "Enable LeakSanitizer." FALSE) +option(USE_MSAN "Enable MemorySanitizer." FALSE) + +set(ENABLED_SANITIZER CACHE INTERNAL BOOL FALSE) +if(USE_ASAN OR USE_MSAN OR USE_LSAN OR USE_MSAN) + set(ENABLED_SANITIZER TRUE) +endif() + + +# -------------------- Stuff to set right away, after having parsed the checkboxes/CLI arguments. set(is_win32_app_linker) -if(WIN32 AND NOT ${WIN32_SPAWN_CONSOLE}) +if(WIN32 AND NOT ${WIN_SPAWN_CONSOLE}) set(is_win32_app_linker WIN32) # if not set, it defaults to console subsystem endif() -# If we have not specified a toolchain, let's detect which one we should use, using the detected arch. -if(NOT TOOLCHAIN_LOADED) - include("cmake/DetectDefaultToolchain.cmake") -endif() # -------------------- Stuff that needs to be executed after PROJECT but before ADD_EXECUTABLE @@ -137,9 +142,9 @@ endif() # TODO: check if Ninja can handle different targets. if(SINGLE_TARGET) # If you want to manually specify the build type, call cmake with parameter: -DCMAKE_BUILD_TYPE=something - # TODO: add NightlyWithDebInfo ? message(STATUS "Single-target build system (${CMAKE_GENERATOR}) detected: generating multiple projects!") + set (CMAKE_BUILD_TYPE "Nightly" CACHE STRING "Set the build type. Expected values: Debug, Nightly or Release.") # Set only if unset. set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Nightly" "Release") if(NOT ${CMAKE_BUILD_TYPE} STREQUAL "") if( diff --git a/cmake/toolchains/Windows-MSVC.cmake b/cmake/toolchains/Windows-MSVC.cmake index 3994a6e7f..4df3bad9f 100644 --- a/cmake/toolchains/Windows-MSVC.cmake +++ b/cmake/toolchains/Windows-MSVC.cmake @@ -34,7 +34,7 @@ function(toolchain_exe_stuff) #-- Configure the Windows application type and add global linker flags. - if(${WIN32_SPAWN_CONSOLE}) + if(${WIN_SPAWN_CONSOLE}) add_link_options("LINKER:/ENTRY:WinMainCRTStartup") # Handled by is_win32_app_linker -> "LINKER:/SUBSYSTEM:CONSOLE" set(PREPROCESSOR_DEFS_EXTRA _WINDOWS_CONSOLE) #ELSE () @@ -102,16 +102,28 @@ function(toolchain_exe_stuff) endif() set(cxx_compiler_flags_common ${cxx_compiler_flags_common} /Zc:preprocessor ${local_msvc_compat_options}) - # Needed, otherwise throws a error... Regression? + # Needed, otherwise throws a error... Regression in CMake? set(CMAKE_C_FLAGS_DEBUG_INIT "" INTERNAL) set(CMAKE_CXX_FLAGS_DEBUG_INIT "" INTERNAL) + if(RUNTIME_STATIC_LINK) + set(local_msvc_cmdline_runtime_lib_debug /MTd) + set(local_msvc_cmdline_runtime_lib_nondebug /MT) + else() + set(local_msvc_cmdline_runtime_lib_debug /MDd) + set(local_msvc_cmdline_runtime_lib_nondebug /MD) + endif() + if(WIN_GENERATE_CRASHDUMP) + set(local_msvc_cmdline_exception_handler /EHa) + else() + set(local_msvc_exception_handler /EHsc) + endif() # gersemi: off target_compile_options(spheresvr PRIVATE ${cxx_compiler_flags_common} - $<$: $,/MT,/MD> /EHa /Oy /GL /GA /Gw /Gy /GF $,/O1 /Zi,/O2>> - $<$: $,/MT,/MD> /EHa /Oy /GL /GA /Gw /Gy /GF $,/O1 /Zi,/O2>> - $<$: $,/MTd,/MDd> /EHsc /Oy- /ob1 /Od /Gs $,/Zi,/ZI>> + $<$: ${local_msvc_cmdline_runtime_lib_nondebug} ${local_msvc_exception_handler} /Oy /GL /GA /Gw /Gy /GF $,/O1 /Zi,/O2>> + $<$: ${local_msvc_cmdline_runtime_lib_nondebug} ${local_msvc_exception_handler} /Oy /GL /GA /Gw /Gy /GF $,/O1 /Zi,/O2>> + $<$: ${local_msvc_cmdline_runtime_lib_debug} /EHsc /Oy- /ob1 /Od /Gs $,/Zi,/ZI>> # ASan (and compilation for ARM arch) doesn't support edit and continue option (ZI) ) # gersemi: on @@ -119,7 +131,6 @@ function(toolchain_exe_stuff) if("${ARCH}" STREQUAL "x86_64") target_compile_options(spheresvr PRIVATE /arch:SSE2) endif() - #-- Apply linker flags. # For some reason only THIS one isn't created, and CMake complains with an error... @@ -143,11 +154,13 @@ function(toolchain_exe_stuff) #-- Set define macros. # Common defines + #gersemi: off target_compile_definitions( spheresvr PRIVATE ${PREPROCESSOR_DEFS_EXTRA} - $<$>:_GITVERSION> + $<$>: + _GITVERSION> _CRT_SECURE_NO_WARNINGS # Temporary setting _CRT_SECURE_NO_WARNINGS to do not spam so much in the build proccess. _EXCEPTIONS_DEBUG @@ -157,15 +170,18 @@ function(toolchain_exe_stuff) # Removing WINSOCK warnings until the code gets updated or reviewed. # Per-build defines $<$>: - NDEBUG> + NDEBUG> $<$: - _NIGHTLYBUILD - THREAD_TRACK_CALLSTACK> + _NIGHTLYBUILD + THREAD_TRACK_CALLSTACK> $<$: - _DEBUG - THREAD_TRACK_CALLSTACK - _PACKETDUMP> + _DEBUG + THREAD_TRACK_CALLSTACK + _PACKETDUMP> + $<$: + WINDOWS_GENERATE_CRASHDUMP> ) + #gersemi: on #-- Custom output directory. diff --git a/cmake/toolchains/include/Windows-Clang_common.inc.cmake b/cmake/toolchains/include/Windows-Clang_common.inc.cmake index a01a37d09..bf2094af3 100644 --- a/cmake/toolchains/include/Windows-Clang_common.inc.cmake +++ b/cmake/toolchains/include/Windows-Clang_common.inc.cmake @@ -14,13 +14,13 @@ endfunction() function(toolchain_exe_stuff_common) #-- Configure the Windows application type and add global linker flags. - if(${WIN32_SPAWN_CONSOLE}) + if(${WIN_SPAWN_CONSOLE}) set(PREPROCESSOR_DEFS_EXTRA _WINDOWS_CONSOLE) if(${CLANG_USE_GCC_LINKER}) # --entry might not work - add_link_options("LINKER:--entry=WinMainCRTStartup") # Handled by is_win32_app_linker -> "LINKER:SHELL:-m$,CONSOLE,WINDOWS>" + add_link_options("LINKER:--entry=WinMainCRTStartup") # Handled by is_win32_app_linker -> "LINKER:SHELL:-m$,CONSOLE,WINDOWS>" else() - add_link_options("LINKER:/ENTRY:WinMainCRTStartup") # Handled by is_win32_app_linker -> "LINKER:SHELL:/SUBSYSTEM:$,CONSOLE,WINDOWS>" + add_link_options("LINKER:/ENTRY:WinMainCRTStartup") # Handled by is_win32_app_linker -> "LINKER:SHELL:/SUBSYSTEM:$,CONSOLE,WINDOWS>" endif() endif() diff --git a/cmake/toolchains/include/Windows-GNU_common.inc.cmake b/cmake/toolchains/include/Windows-GNU_common.inc.cmake index 0dfdb2968..c2a90d51f 100644 --- a/cmake/toolchains/include/Windows-GNU_common.inc.cmake +++ b/cmake/toolchains/include/Windows-GNU_common.inc.cmake @@ -9,7 +9,7 @@ function(toolchain_exe_stuff_common) #-- Configure the Windows application type. # Subsystem is already managed by is_win32_app_linker. GCC doesn't need us to specify the entry point. - #IF (${WIN32_SPAWN_CONSOLE}) + #IF (${WIN_SPAWN_CONSOLE}) # add_link_options ("LINKER:SHELL:-mconsole") # SET (PREPROCESSOR_DEFS_EXTRA _WINDOWS_CONSOLE) ##ELSE () diff --git a/src/common/CException.h b/src/common/CException.h index b141afcd3..4a121107f 100644 --- a/src/common/CException.h +++ b/src/common/CException.h @@ -13,13 +13,13 @@ # define WINDOWS_HAS_SEH 1 #endif -#if defined (WINDOWS_HAS_SEH) && defined(_NIGHTLYBUILD) +#if defined(WINDOWS_HAS_SEH) && defined(WINDOWS_GENERATE_CRASHDUMP) // We don't want this for Release build because, in order to call _set_se_translator, we should set the /EHa // compiler flag, which slows down code a bit. # define WINDOWS_SPHERE_SHOULD_HANDLE_STRUCTURED_EXCEPTIONS 1 -#endif +//#endif -#if defined(WINDOWS_SPHERE_SHOULD_HANDLE_STRUCTURED_EXCEPTIONS) && !defined(_NO_CRASHDUMP) +//2#if defined(WINDOWS_SPHERE_SHOULD_HANDLE_STRUCTURED_EXCEPTIONS) && defined(WINDOWS_GENERATE_CRASHDUMP) // Also, the crash dump generating code works only when Structured Exception Handling is enabled # define WINDOWS_SHOULD_EMIT_CRASH_DUMP 1 #endif diff --git a/src/common/crashdump/crashdump.h b/src/common/crashdump/crashdump.h index 5de0b33ef..401727ee7 100644 --- a/src/common/crashdump/crashdump.h +++ b/src/common/crashdump/crashdump.h @@ -3,6 +3,8 @@ #include +// TODO: enable creation of the crash dump also for mingw, since it can manage windows structured exceptions. + #ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN // include just windows.h without the other winapi headers, we'll add them manually when needed #endif diff --git a/src/common/sphere_library/CSFile.cpp b/src/common/sphere_library/CSFile.cpp index 513bf8793..b652df0ec 100644 --- a/src/common/sphere_library/CSFile.cpp +++ b/src/common/sphere_library/CSFile.cpp @@ -438,14 +438,17 @@ CSString CSFile::GetMergedFileName( lpctstr pszBase, lpctstr pszName ) // static size_t len = 0; if ( pszBase && pszBase[0] ) { - len = Str_CopyLimitNull( ptcFilePath, pszBase, sizeof(ptcFilePath) - 1); // eventually, leave space for the (back)slash - if (len && ptcFilePath[len - 1] != '\\' && ptcFilePath[len - 1] != '/') + len = Str_CopyLimitNull(ptcFilePath, pszBase, sizeof(ptcFilePath) - 1); // eventually, leave space for the (back)slash + if ((len > 1) && (ptcFilePath[len - 1] != '\\') && (ptcFilePath[len - 1] != '/')) { + // Append the slash/backslash, overwriting the string terminator. #ifdef _WIN32 ptcFilePath[len] = '\\'; #else ptcFilePath[len] = '/'; #endif + // Add back the string terminator. We're sure we won't overflow since we passed sizeof(ptcFilePath) - 1. + ptcFilePath[len + 1] = '\0'; } } else diff --git a/src/game/CServer.cpp b/src/game/CServer.cpp index 5e35bacd6..e821780e3 100644 --- a/src/game/CServer.cpp +++ b/src/game/CServer.cpp @@ -2361,7 +2361,7 @@ bool CServer::CommandLine( int argc, tchar * argv[] ) } } continue; -#if defined(_WIN32) && !defined(_DEBUG) && !defined(_NO_CRASHDUMP) +#if defined(_WIN32) && !defined(_DEBUG) && defined(WINDOWS_GENERATE_CRASHDUMP) case 'E': CrashDump::Enable(); if (CrashDump::IsEnabled()) diff --git a/src/game/spheresvr.cpp b/src/game/spheresvr.cpp index 12708dc69..6f7fdeb5a 100644 --- a/src/game/spheresvr.cpp +++ b/src/game/spheresvr.cpp @@ -207,16 +207,16 @@ bool MainThread::shouldExit() noexcept static bool WritePidFile(int iMode = 0) { - lpctstr file = SPHERE_FILE ".pid"; + lpctstr fileName = SPHERE_FILE ".pid"; FILE* pidFile; if (iMode == 1) // delete { - return (STDFUNC_UNLINK(file) == 0); + return (STDFUNC_UNLINK(fileName) == 0); } else if (iMode == 2) // check for .pid file { - pidFile = fopen(file, "r"); + pidFile = fopen(fileName, "r"); if (pidFile) { g_Log.Event(LOGM_INIT, SPHERE_FILE ".pid already exists. Secondary launch or unclean shutdown?\n"); @@ -226,7 +226,7 @@ static bool WritePidFile(int iMode = 0) } else { - pidFile = fopen(file, "w"); + pidFile = fopen(fileName, "w"); if (pidFile) { pid_t spherepid = STDFUNC_GETPID(); diff --git a/src/sphere/threads.cpp b/src/sphere/threads.cpp index 9eb3d26f6..aacad6db1 100644 --- a/src/sphere/threads.cpp +++ b/src/sphere/threads.cpp @@ -178,7 +178,8 @@ void ThreadHolder::push(AbstractThread *thread) noexcept { //throw CSError(LOGL_FATAL, 0, "AbstractThread not being an AbstractSphereThread?"); STDERR_LOG("AbstractThread not being an AbstractSphereThread?"); - fExceptionThrown = true; + //fExceptionThrown = true; + goto soft_throw; } std::unique_lock lock(m_mutex); @@ -223,6 +224,7 @@ void ThreadHolder::push(AbstractThread *thread) noexcept if (fExceptionThrown) { +soft_throw: // Should never happen. RaiseImmediateAbort(); } From 621c62d5f92e3c09756ef90295f04f372cdab249 Mon Sep 17 00:00:00 2001 From: cbnolok Date: Sun, 13 Oct 2024 18:22:11 +0200 Subject: [PATCH 26/32] Fixed settings DIR and FLAGS not sending a full client update, minor change to client update packet. --- src/common/common.h | 27 +++++++++++++++++ src/common/resource/sections/CSkillDef.cpp | 6 ++-- src/common/sphere_library/CSObjList.cpp | 14 +++++++-- src/game/CObjBaseTemplate.h | 6 ++-- src/game/CSector.cpp | 2 +- src/game/CServer.cpp | 3 +- src/game/chars/CChar.cpp | 21 ++++++++----- src/game/chars/CChar.h | 12 +++++--- src/game/chars/CCharAct.cpp | 14 ++++----- src/game/chars/CCharNotoriety.cpp | 4 +-- src/game/chars/CCharSkill.cpp | 2 +- src/game/chars/CCharSpell.cpp | 6 ++-- src/game/chars/CCharStatus.cpp | 5 ++-- src/game/clients/CClientEvent.cpp | 2 +- src/game/items/CItem.cpp | 35 ++++++++++++++-------- src/game/items/CItem.h | 6 ++-- src/network/CClientIterator.cpp | 18 +++++++++++ src/network/CNetState.cpp | 2 +- src/network/CNetworkManager.cpp | 5 ++-- src/network/send.cpp | 6 ++-- 20 files changed, 138 insertions(+), 58 deletions(-) diff --git a/src/common/common.h b/src/common/common.h index 9932c6fd5..1b20d9a8b 100644 --- a/src/common/common.h +++ b/src/common/common.h @@ -140,6 +140,27 @@ constexpr T sign(const T n) noexcept #define maximum(x,y) ((x)>(y)?(x):(y)) // NOT to be used with functions! Store the result of the function in a variable first, otherwise the function will be executed twice! #define medium(x,y,z) ((x)>(y)?(x):((z)<(y)?(z):(y))) // NOT to be used with functions! Store the result of the function in a variable first, otherwise the function will be executed twice! +template +[[nodiscard]] +constexpr T saturating_sub(T a, T b) noexcept { + // Saturating subtraction. + + // Ensure T is an arithmetic type + static_assert(std::is_arithmetic_v, "T must be an arithmetic type"); + + // For unsigned types + if constexpr (std::is_unsigned_v) + return (a > b) ? a - b : 0; + // For signed types + else + { + if (b > 0 && a < std::numeric_limits::min() + b) + return std::numeric_limits::min(); // Saturate to minimum + return a - b; + } +} + +#define SATURATING_SUB_SELF(var, val) var = saturating_sub(var, val) /* End of arithmetic code */ @@ -197,6 +218,12 @@ constexpr void UnreferencedParameter(T const&) noexcept { #define FALLTHROUGH [[fallthrough]] #define NODISCARD [[nodiscard]] +#if defined(__GNUC__) || defined(__clang__) +# define RETURNS_NOTNULL [[gnu::returns_nonnull]] +#else +# define RETURNS_NOTNULL +#endif + #ifdef _DEBUG #define NOEXCEPT_NODEBUG #else diff --git a/src/common/resource/sections/CSkillDef.cpp b/src/common/resource/sections/CSkillDef.cpp index e64bebc22..621a75f53 100644 --- a/src/common/resource/sections/CSkillDef.cpp +++ b/src/common/resource/sections/CSkillDef.cpp @@ -191,10 +191,10 @@ bool CSkillDef::r_LoadVal( CScript &s ) m_vcDelay.Load( s.GetArgStr()); break; case SKC_FLAGS: - m_dwFlags = s.GetArgVal(); + m_dwFlags = s.GetArgDWVal(); break; case SKC_GROUP: - m_dwGroup = s.GetArgVal(); + m_dwGroup = s.GetArgDWVal(); break; case SKC_EFFECT: m_vcEffect.Load( s.GetArgStr()); @@ -246,4 +246,4 @@ bool CSkillDef::r_LoadVal( CScript &s ) EXC_ADD_SCRIPT; EXC_DEBUG_END; return false; -} \ No newline at end of file +} diff --git a/src/common/sphere_library/CSObjList.cpp b/src/common/sphere_library/CSObjList.cpp index 35fafb63d..a66cad392 100644 --- a/src/common/sphere_library/CSObjList.cpp +++ b/src/common/sphere_library/CSObjList.cpp @@ -56,18 +56,26 @@ CSObjListRec * CSObjList::GetContentAt( size_t index ) const void CSObjList::ClearContainer() { // delete all entries. + bool fSuccess = false; EXC_TRY("Deleting objects scheduled for deletion"); for (;;) // iterate the list. { CSObjListRec * pRec = GetContainerHead(); - if ( pRec == nullptr ) - break; + if ( pRec == nullptr ) { + fSuccess = true; + break; + } ASSERT( pRec->GetParent() == this ); delete pRec; } EXC_CATCH; - m_uiCount = 0; + if (fSuccess) { + ASSERT(m_uiCount == 0); + } + else { + m_uiCount = 0; + } m_pHead = nullptr; m_pTail = nullptr; } diff --git a/src/game/CObjBaseTemplate.h b/src/game/CObjBaseTemplate.h index af8a2ec44..adb470413 100644 --- a/src/game/CObjBaseTemplate.h +++ b/src/game/CObjBaseTemplate.h @@ -71,10 +71,12 @@ class CObjBaseTemplate : public CSObjContRec virtual int IsWeird() const; // Parent objects - virtual const CObjBaseTemplate* GetTopLevelObj() const { + [[nodiscard]] RETURNS_NOTNULL + virtual const CObjBaseTemplate* GetTopLevelObj() const { return this; } - virtual CObjBaseTemplate* GetTopLevelObj() { + [[nodiscard]] RETURNS_NOTNULL + virtual CObjBaseTemplate* GetTopLevelObj() { return this; } diff --git a/src/game/CSector.cpp b/src/game/CSector.cpp index bf6402cfe..c931c7715 100644 --- a/src/game/CSector.cpp +++ b/src/game/CSector.cpp @@ -284,7 +284,7 @@ bool CSector::r_LoadVal( CScript &s ) SetWeatherChance( false, s.HasArgs() ? s.GetArgVal() : -1 ); return true; case SC_FLAGS: - m_dwFlags = s.GetArgVal(); + m_dwFlags = s.GetArgDWVal(); return true; case SC_LIGHT: if ( g_Cfg.m_fAllowLightOverride ) diff --git a/src/game/CServer.cpp b/src/game/CServer.cpp index e821780e3..007c9890d 100644 --- a/src/game/CServer.cpp +++ b/src/game/CServer.cpp @@ -2540,7 +2540,8 @@ void CServer::_OnTick() EXC_TRY("Tick"); #ifndef _WIN32 - if (g_UnixTerminal.isReady()) + // This happens on T_Main, and not on T_UnixTerm. + if (g_UnixTerminal.isReady()) { tchar c = g_UnixTerminal.read(); if ( OnConsoleKey(m_sConsoleText, c, false) == 2 ) diff --git a/src/game/chars/CChar.cpp b/src/game/chars/CChar.cpp index 4a327c08a..a4ac213d8 100644 --- a/src/game/chars/CChar.cpp +++ b/src/game/chars/CChar.cpp @@ -1642,7 +1642,7 @@ void CChar::SetID( CREID_TYPE id ) if ( pHand ) GetPackSafe()->ContentAdd(pHand); } - UpdateMode(nullptr, true); + UpdateMode(true, nullptr); } @@ -3828,7 +3828,6 @@ bool CChar::r_LoadVal( CScript & s ) DIR_TYPE dir = static_cast(s.GetArgVal()); if (dir <= DIR_INVALID || dir >= DIR_QTY) dir = DIR_SE; - m_dirFace = dir; UpdateDir( dir ); } break; @@ -3856,8 +3855,16 @@ bool CChar::r_LoadVal( CScript & s ) break; } // Don't modify STATF_SAVEPARITY, STATF_PET, STATF_SPAWNED here - _uiStatFlag = (_uiStatFlag & (STATF_SAVEPARITY | STATF_PET | STATF_SPAWNED)) | (s.GetArgLLVal() & ~(STATF_SAVEPARITY | STATF_PET | STATF_SPAWNED)); - NotoSave_Update(); + static constexpr auto uiFlagsNoChange = (STATF_SAVEPARITY | STATF_PET | STATF_SPAWNED); + static constexpr auto uiFlagsRequireFullUpdate = (STATF_STONE | STATF_HIDDEN | STATF_DEAD); + const auto uiCurFlags = _uiStatFlag; + const auto uiNewFlags = s.GetArgULLVal(); + _uiStatFlag = (_uiStatFlag & uiFlagsNoChange) | (uiNewFlags & ~uiFlagsNoChange); + if (uiCurFlags != uiNewFlags) + { + const bool fDoFullUpdate = (uiCurFlags & uiFlagsRequireFullUpdate) != (uiNewFlags & uiFlagsRequireFullUpdate); + NotoSave_Update(fDoFullUpdate); + } break; } case CHC_FONT: @@ -4010,7 +4017,7 @@ bool CChar::r_LoadVal( CScript & s ) StatFlag_Mod(STATF_STONE,fSet); if ( fChange ) { - UpdateMode(nullptr, true); + UpdateMode(true, nullptr); if ( IsClientActive() ) m_pClient->addCharMove(this); } @@ -4636,7 +4643,7 @@ bool CChar::r_Verb( CScript &s, CTextConsole * pSrc ) // Execute command from sc if ( pSrc ) { _uiStatFlag = s.GetArgLLFlag( _uiStatFlag, STATF_INSUBSTANTIAL ); - UpdateMode(nullptr, true); + UpdateMode(true, nullptr); if ( IsStatFlag(STATF_INSUBSTANTIAL) ) { if ( IsClientActive() ) @@ -4923,7 +4930,7 @@ bool CChar::r_Verb( CScript &s, CTextConsole * pSrc ) // Execute command from sc if ( ! IsPlayableCharacter()) return false; SetHue( GetHue() ^ HUE_UNDERWEAR /*, false, pSrc*/ ); //call @Dye on underwear? - UpdateMode(); + UpdateMode(true, nullptr); break; case CHV_UNEQUIP: // uid return ItemBounce( CUID::ItemFindFromUID(s.GetArgVal()) ); diff --git a/src/game/chars/CChar.h b/src/game/chars/CChar.h index 3ea4fa13f..35a5edff1 100644 --- a/src/game/chars/CChar.h +++ b/src/game/chars/CChar.h @@ -495,8 +495,10 @@ public: void StatFlag_Mod(uint64 uiStatFlag, bool fMod) noexcept; bool IsVerticalSpace( const CPointMap& ptDest, bool fForceMount = false ) const; public: - virtual CObjBaseTemplate* GetTopLevelObj() override; - virtual const CObjBaseTemplate* GetTopLevelObj() const override; + [[nodiscard]] RETURNS_NOTNULL + virtual CObjBaseTemplate* GetTopLevelObj() override; + [[nodiscard]] RETURNS_NOTNULL + virtual const CObjBaseTemplate* GetTopLevelObj() const override; bool IsSwimming() const; bool MoveToRegion(CRegionWorld* pNewArea, bool fAllowReject); @@ -555,7 +557,7 @@ public: void StatFlag_Mod(uint64 uiStatFlag, bool fMod) noexcept; ANIM_TYPE GenerateAnimate(ANIM_TYPE action, bool fTranslate = true, bool fBackward = false, byte iFrameDelay = 0, byte iAnimLen = 7); bool UpdateAnimate(ANIM_TYPE action, bool fTranslate = true, bool fBackward = false, byte iFrameDelay = 0, byte iAnimLen = 7); - void UpdateMode( CClient * pExcludeClient = nullptr, bool fFull= false ); + void UpdateMode( bool fFull, CClient * pExcludeClient = nullptr); void UpdateSpeedMode(); void UpdateVisualRange(); void UpdateMove( const CPointMap & ptOld, CClient * pClientExclude = nullptr, bool bFull = false ); @@ -821,8 +823,10 @@ public: void StatFlag_Mod(uint64 uiStatFlag, bool fMod) noexcept; /** * @brief Clearing notoriety and update myself so everyone checks my noto again. + * + * @param fCharFullUpdate Should it do a full character entity update instead of a partial one? */ - void NotoSave_Update(); + void NotoSave_Update(bool fCharFullUpdate = false); /** * @brief Deleting myself and sending data again for given char. diff --git a/src/game/chars/CCharAct.cpp b/src/game/chars/CCharAct.cpp index e07bd77c0..b4c427f1a 100644 --- a/src/game/chars/CCharAct.cpp +++ b/src/game/chars/CCharAct.cpp @@ -2428,7 +2428,7 @@ bool CChar::UpdateAnimate(ANIM_TYPE action, bool fTranslate, bool fBackward , by // If character status has been changed // (Polymorph, war mode or hide), resend him -void CChar::UpdateMode( CClient * pExcludeClient, bool fFull ) +void CChar::UpdateMode( bool fFull, CClient * pExcludeClient ) { ADDTOCALLSTACK("CChar::UpdateMode"); @@ -3524,7 +3524,7 @@ bool CChar::Reveal( uint64 iFlags ) return false; m_StepStealth = 0; - UpdateMode(nullptr, true); + UpdateMode(true, nullptr); SysMessageDefault(DEFMSG_HIDING_REVEALED); return true; } @@ -4222,8 +4222,6 @@ bool CChar::SetPoison( int iSkill, int iHits, CChar * pCharSrc ) } } - - CClient *pClient = GetClientActive(); if ( pClient && IsSetOF(OF_Buffs) ) { @@ -4253,7 +4251,7 @@ void CChar::Wake() RaiseCorpse(pCorpse); StatFlag_Clear(STATF_SLEEPING); - UpdateMode(); + UpdateMode(false, nullptr); } // Sleep @@ -4277,7 +4275,7 @@ void CChar::SleepStart( bool fFrontFall ) SetID(_iPrev_id); StatFlag_Set(STATF_SLEEPING); StatFlag_Clear(STATF_HIDDEN); - UpdateMode(); + UpdateMode(false, nullptr); } // We died, calling @Death, removing trade windows. @@ -4406,7 +4404,7 @@ CChar::DeathRequestResult CChar::Death() if ( m_pNPC->m_bonded ) { m_CanMask |= CAN_C_GHOST; - UpdateMode(nullptr, true); + UpdateMode(true, nullptr); return DeathRequestResult::Success; } @@ -5686,7 +5684,7 @@ void CChar::OnTickStatusUpdate() if ( m_fStatusUpdate & SU_UPDATE_MODE ) { - UpdateMode(); + UpdateMode(false, nullptr); m_fStatusUpdate &= ~SU_UPDATE_MODE; } diff --git a/src/game/chars/CCharNotoriety.cpp b/src/game/chars/CCharNotoriety.cpp index e5d561103..c3880442b 100644 --- a/src/game/chars/CCharNotoriety.cpp +++ b/src/game/chars/CCharNotoriety.cpp @@ -712,13 +712,13 @@ void CChar::NotoSave_Clear() m_notoSaves.clear(); } -void CChar::NotoSave_Update() +void CChar::NotoSave_Update(bool fCharFullUpdate) { //ADDTOCALLSTACK_DEBUG("CChar::NotoSave_Update"); EXC_TRY("NotoSave_Update"); NotoSave_Clear(); - UpdateMode(); + UpdateMode(fCharFullUpdate, nullptr); UpdatePropertyFlag(); EXC_CATCH; diff --git a/src/game/chars/CCharSkill.cpp b/src/game/chars/CCharSkill.cpp index 5721611b1..fe11e036f 100644 --- a/src/game/chars/CCharSkill.cpp +++ b/src/game/chars/CCharSkill.cpp @@ -2438,7 +2438,7 @@ int CChar::Skill_Hiding( SKTRIG_TYPE stage ) ObjMessage(g_Cfg.GetDefaultMsg(DEFMSG_HIDING_SUCCESS), this); StatFlag_Set(STATF_HIDDEN); Reveal(STATF_INVISIBLE); // clear previous invisibility spell effect (this will not reveal the char because STATF_HIDDEN still set) - UpdateMode(nullptr, true); + UpdateMode(true, nullptr); if ( IsClientActive() ) { GetClientActive()->removeBuff( BI_HIDDEN ); diff --git a/src/game/chars/CCharSpell.cpp b/src/game/chars/CCharSpell.cpp index 8e7d62f1f..d68bf7da3 100644 --- a/src/game/chars/CCharSpell.cpp +++ b/src/game/chars/CCharSpell.cpp @@ -701,7 +701,7 @@ void CChar::Spell_Effect_Remove(CItem * pSpell) case LAYER_SPELL_Paralyze: StatFlag_Clear(STATF_FREEZE); - UpdateMode(); // immediately tell the client that now he's able to move (without this, it will be able to move only on next tick update) + UpdateMode(false, nullptr); // immediately tell the client that now he's able to move (without this, it will be able to move only on next tick update) if (pClient) pClient->removeBuff(BI_PARALYZE); return; @@ -1183,7 +1183,7 @@ void CChar::Spell_Effect_Add( CItem * pSpell ) StatFlag_Set(STATF_INVISIBLE); Reveal(STATF_HIDDEN); // clear previous Hiding skill effect (this will not reveal the char because STATF_Invisibility still set) UpdateModeFlag(); - UpdateMode(nullptr, true); + UpdateMode(true, nullptr); if (pClient && IsSetOF(OF_Buffs)) { pClient->removeBuff(BI_INVISIBILITY); @@ -1192,7 +1192,7 @@ void CChar::Spell_Effect_Add( CItem * pSpell ) return; case LAYER_SPELL_Paralyze: StatFlag_Set(STATF_FREEZE); - UpdateMode(); + UpdateMode(false, nullptr); if (pClient && IsSetOF(OF_Buffs)) { pClient->removeBuff(BI_PARALYZE); diff --git a/src/game/chars/CCharStatus.cpp b/src/game/chars/CCharStatus.cpp index 2dd9cfbdd..32c20165e 100644 --- a/src/game/chars/CCharStatus.cpp +++ b/src/game/chars/CCharStatus.cpp @@ -486,13 +486,14 @@ int CChar::GetStatPercent(STAT_TYPE i) const return IMulDiv(Stat_GetVal(i), 100, maxval); } - +[[nodiscard]] RETURNS_NOTNULL const CObjBaseTemplate* CChar::GetTopLevelObj() const { // Get the object that has a location in the world. (Ground level) return this; } +[[nodiscard]] RETURNS_NOTNULL CObjBaseTemplate* CChar::GetTopLevelObj() { // Get the object that has a location in the world. (Ground level) @@ -692,7 +693,7 @@ byte CChar::GetModeFlag( const CClient *pViewer ) const iFlags |= STATF_INVISIBLE; if ( IsStatFlag(iFlags) ) // Checking if I have any of these settings enabled on the ini and I have any of them, if so ... CHARMODE_INVIS is set and color applied. - mode |= CHARMODE_INVIS; //When sending CHARMODE_INVIS state to client, your character anim are grey + mode |= CHARMODE_INVIS; //When sending CHARMODE_INVIS state to client, your character anim are grey return mode; } diff --git a/src/game/clients/CClientEvent.cpp b/src/game/clients/CClientEvent.cpp index 84177d14d..c4ecc42ff 100644 --- a/src/game/clients/CClientEvent.cpp +++ b/src/game/clients/CClientEvent.cpp @@ -1032,7 +1032,7 @@ void CClient::Event_CombatMode( bool fWar ) // Only for switching to combat mode } addPlayerWarMode(); - m_pChar->UpdateMode( this, m_pChar->IsStatFlag( STATF_DEAD )); + m_pChar->UpdateMode(m_pChar->IsStatFlag(STATF_DEAD), this); } bool CClient::Event_Command(lpctstr pszCommand, TALKMODE_TYPE mode) diff --git a/src/game/items/CItem.cpp b/src/game/items/CItem.cpp index 4c1277f08..fba785497 100644 --- a/src/game/items/CItem.cpp +++ b/src/game/items/CItem.cpp @@ -367,7 +367,7 @@ CItem * CItem::CreateBase( ITEMID_TYPE id, IT_TYPE type ) // static ASSERT(pItem); pItem->SetType(type, false); - if (idErrorMsg && idErrorMsg != (ITEMID_TYPE)-1) + if (idErrorMsg && idErrorMsg != (ITEMID_TYPE)-1) DEBUG_ERR(("CreateBase invalid item ID=0%" PRIx32 ", defaulting to ID=0%" PRIx32 ". Created UID=0%" PRIx32 "\n", idErrorMsg, id, (dword)pItem->GetUID())); return pItem; @@ -1953,9 +1953,17 @@ lpctstr CItem::GetNameFull( bool fIdentified ) const // Who is it stolen from ? const CChar * pChar = m_uidLink.CharFind(); if ( pChar ) - len += snprintf(pTemp + len, Str_TempLength() - len, " (%s %s)", g_Cfg.GetDefaultMsg( DEFMSG_ITEMTITLE_STOLEN_FROM ), pChar->GetName()); - else - len += snprintf(pTemp + len, Str_TempLength() - len, " (%s)", g_Cfg.GetDefaultMsg( DEFMSG_ITEMTITLE_STOLEN ) ); + { + /*len +=*/ snprintf(pTemp + len, Str_TempLength() - len, + " (%s %s)", + g_Cfg.GetDefaultMsg( DEFMSG_ITEMTITLE_STOLEN_FROM ), pChar->GetName()); + } + else + { + /*len +=*/ snprintf(pTemp + len, Str_TempLength() - len, + " (%s)", + g_Cfg.GetDefaultMsg( DEFMSG_ITEMTITLE_STOLEN ) ); + } } return pTemp; @@ -4097,6 +4105,7 @@ CItem* CItem::GetTopContainer() return (pItem == this) ? nullptr : pItem; } +[[nodiscard]] RETURNS_NOTNULL const CObjBaseTemplate* CItem::GetTopLevelObj() const { // recursively get the item that is at "top" level. @@ -4108,6 +4117,7 @@ const CObjBaseTemplate* CItem::GetTopLevelObj() const return pObj->GetTopLevelObj(); } +[[nodiscard]] RETURNS_NOTNULL CObjBaseTemplate* CItem::GetTopLevelObj() { // recursively get the item that is at "top" level. @@ -5060,7 +5070,8 @@ lpctstr CItem::Use_SpyGlass( CChar * pUser ) const WEATHER_TYPE wtWeather = ptCoords.GetSector()->GetWeather(); byte iLight = ptCoords.GetSector()->GetLight(); CSString sSearch; - tchar *pResult = Str_GetTemp(); + tchar *pResult = Str_GetTemp(); + size_t uiResultStrAvailableLen = Str_TempLength(); // Weather bonus double rWeatherSight = wtWeather == WEATHER_RAIN ? (0.25 * bSight) : 0.0; @@ -5118,7 +5129,7 @@ lpctstr CItem::Use_SpyGlass( CChar * pUser ) const sSearch = g_Cfg.GetDefaultMsg(DEFMSG_USE_SPYGLASS_WEATHER); else sSearch = g_Cfg.GetDefaultMsg(DEFMSG_USE_SPYGLASS_NO_LAND); - Str_CopyLimitNull( pResult, sSearch, Str_TempLength() ); + SATURATING_SUB_SELF(uiResultStrAvailableLen, Str_CopyLimitNull( pResult, sSearch, uiResultStrAvailableLen )); break; } @@ -5182,7 +5193,7 @@ lpctstr CItem::Use_SpyGlass( CChar * pUser ) const sSearch.Format(g_Cfg.GetDefaultMsg(DEFMSG_SHIP_SEEN_SHIP_SINGLE), pBoatSighted->GetName(), CPointBase::sm_szDirs[dir]); else sSearch.Format(g_Cfg.GetDefaultMsg(DEFMSG_SHIP_SEEN_SHIP_MANY), CPointBase::sm_szDirs[dir]); - strcat( pResult, sSearch); + SATURATING_SUB_SELF(uiResultStrAvailableLen, Str_ConcatLimitNull(pResult, sSearch, uiResultStrAvailableLen)); } if (iItemSighted) // Report item sightings, also boats beyond the boat visibility range in the radar screen @@ -5203,8 +5214,8 @@ lpctstr CItem::Use_SpyGlass( CChar * pUser ) const else sSearch.Format(g_Cfg.GetDefaultMsg(DEFMSG_SHIP_SEEN_SPECIAL_DIR), pItemSighted->GetNameFull(false), static_cast(CPointBase::sm_szDirs[ dir ])); } - strcat( pResult, sSearch); - } + SATURATING_SUB_SELF(uiResultStrAvailableLen, Str_ConcatLimitNull(pResult, sSearch, uiResultStrAvailableLen)); + } // Check for creatures Area->RestartSearch(); @@ -5238,8 +5249,8 @@ lpctstr CItem::Use_SpyGlass( CChar * pUser ) const sSearch.Format(g_Cfg.GetDefaultMsg(DEFMSG_SHIP_SEEN_CREAT_SINGLE), CPointBase::sm_szDirs[dir] ); else sSearch.Format(g_Cfg.GetDefaultMsg(DEFMSG_SHIP_SEEN_CREAT_MANY), CPointBase::sm_szDirs[dir] ); - strcat( pResult, sSearch); - } + Str_ConcatLimitNull(pResult, sSearch, uiResultStrAvailableLen); + } return pResult; } @@ -5553,7 +5564,7 @@ bool CItem::OnSpellEffect( SPELL_TYPE spell, CChar * pCharSrc, int iSkillLevel, spell = (SPELL_TYPE)(Args.m_iN1); iSkillLevel = (int)(Args.m_iN2); pSpellDef = g_Cfg.GetSpellDef( spell ); - + ASSERT(pSpellDef); if ( IsType(IT_WAND) ) // try to recharge the wand. { diff --git a/src/game/items/CItem.h b/src/game/items/CItem.h index 1ee537082..7377fdc5a 100644 --- a/src/game/items/CItem.h +++ b/src/game/items/CItem.h @@ -770,8 +770,10 @@ protected: virtual void _SetTimeout(int64 iMsecs) override final; bool MoveToCheck(const CPointMap & pt, CChar * pCharMover = nullptr ); virtual bool MoveNearObj( const CObjBaseTemplate *pItem, ushort uiSteps = 0 ) override; - virtual CObjBaseTemplate* GetTopLevelObj() override; - virtual const CObjBaseTemplate* GetTopLevelObj() const override; + [[nodiscard]] RETURNS_NOTNULL + virtual CObjBaseTemplate* GetTopLevelObj() override; + [[nodiscard]] RETURNS_NOTNULL + virtual const CObjBaseTemplate* GetTopLevelObj() const override; CObjBase * GetContainer() const noexcept; CItem * GetTopContainer(); diff --git a/src/network/CClientIterator.cpp b/src/network/CClientIterator.cpp index ee861577b..93e9e4d25 100644 --- a/src/network/CClientIterator.cpp +++ b/src/network/CClientIterator.cpp @@ -8,6 +8,24 @@ ClientIterator::ClientIterator(const CNetworkManager* network) { m_network = (network == nullptr ? &g_NetworkManager : network); m_nextClient = static_cast (m_network->m_clients.GetContainerHead()); + +#ifdef _DEBUG + const uint uiCnt = (uint)g_NetworkManager.m_clients.GetContentCount(); + //g_Log.EventWarn("Client count: %u.\n", uiCnt); + uint uiCntReal = 0; + if (CClient *pCliLoop = m_nextClient) + { + //g_Log.EventEvent("Start counting.\n"); + do ++ uiCntReal; + while ((pCliLoop = pCliLoop->GetNext()) != nullptr); + } + //g_Log.EventWarn("Actual clients in list: %u.\n", uiCntReal); + if (uiCnt != uiCntReal) + { + g_Log.EventWarn("Client count mismatch!.\n"); + EXC_NOTIFY_DEBUGGER; + } +#endif } ClientIterator::~ClientIterator() diff --git a/src/network/CNetState.cpp b/src/network/CNetState.cpp index 8623ed7c7..eec21d7fb 100644 --- a/src/network/CNetState.cpp +++ b/src/network/CNetState.cpp @@ -54,8 +54,8 @@ void CNetState::clear(void) { g_Serv.StatDec(SERV_STAT_CLIENTS); + static constexpr LOG_TYPE logFlags = enum_alias_cast(LOGM_NOCONTEXT | LOGM_CLIENTS_LOG | LOGL_EVENT); const CONNECT_TYPE connectionType = m_client->GetConnectType(); - const LOG_TYPE logFlags = enum_alias_cast(LOGM_NOCONTEXT | LOGM_CLIENTS_LOG | LOGL_EVENT); const size_t uiClients = g_Serv.StatGet(SERV_STAT_CLIENTS); const lpctstr ptcAddress = m_peerAddress.GetAddrStr(); if (connectionType == CONNECT_LOGIN) diff --git a/src/network/CNetworkManager.cpp b/src/network/CNetworkManager.cpp index c2ee43980..ca558b289 100644 --- a/src/network/CNetworkManager.cpp +++ b/src/network/CNetworkManager.cpp @@ -426,10 +426,11 @@ void CNetworkManager::tick(void) if (!pClient || (pClient->GetConnectType() == CONNECT_UNK)) { const int64 iTimeSinceConnectionMs = iCurSysTimeMs - state->m_iConnectionTimeMs; - if (iTimeSinceConnectionMs > g_Cfg._iTimeoutIncompleteConnectionMs) + const int64 iTimeoutIncompleteConnectionMs = g_Cfg._iTimeoutIncompleteConnectionMs; + if (iTimeSinceConnectionMs > iTimeoutIncompleteConnectionMs) { EXC_SET_BLOCK("mark closed for timeout"); - g_Log.Event(LOGM_CLIENTS_LOG | LOGL_EVENT, + g_Log.Event(LOGM_CLIENTS_LOG | LOGL_WARN, // LOGM_NOCONTEXT "%x:Force closing connection from IP %s. Reason: timed out before completing login.\n", state->id(), state->m_peerAddress.GetAddrStr()); //state->markReadClosed(); diff --git a/src/network/send.cpp b/src/network/send.cpp index b70bc8527..50856ed42 100644 --- a/src/network/send.cpp +++ b/src/network/send.cpp @@ -134,7 +134,7 @@ PacketObjectStatus::PacketObjectStatus(const CClient* target, CObjBase* object) const CNetState * state = target->GetNetState(); const CChar *character = target->GetChar(); - CChar *objectChar = object->IsChar() ? static_cast(object) : nullptr; + CChar *objectChar = object->IsChar() ? static_cast(object) : nullptr; bool fCanRename = false; byte version = 0; @@ -199,7 +199,7 @@ PacketObjectStatus::PacketObjectStatus(const CClient* target, CObjBase* object) writeInt16(iHitsMax); // Max hit points writeBool(fCanRename); writeByte(version); - if (state->isClientEnhanced() && objectChar && objectChar->IsPlayableCharacter()) + if (state->isClientEnhanced() && objectChar && objectChar->IsClientType() /*objectChar->IsPlayableCharacter()*/) { // The Enhanced Client wants the char race and other things when showing paperdolls (otherwise the interface throws an "unnoticeable" internal error) WriteVersionSpecific(target, objectChar, version); @@ -211,7 +211,7 @@ PacketObjectStatus::PacketObjectStatus(const CClient* target, CObjBase* object) void PacketObjectStatus::WriteVersionSpecific(const CClient* target, CChar* other, byte version) { - bool fElemental = IsSetCombatFlags(COMBAT_ELEMENTAL_ENGINE); + const bool fElemental = IsSetCombatFlags(COMBAT_ELEMENTAL_ENGINE); const CCharBase * otherDefinition = other->Char_GetDef(); const CCPropsChar* pCCPChar = other->GetComponentProps(); const CCPropsChar* pBaseCCPChar = otherDefinition->GetComponentProps(); From 8d57444f5b59108b26dff2bf752bf5965f0674b7 Mon Sep 17 00:00:00 2001 From: Jhobean <51728381+Jhobean@users.noreply.github.com> Date: Mon, 14 Oct 2024 05:16:28 -0400 Subject: [PATCH 27/32] Add @petrelease trigger (#1302) --- Changelog.txt | 3 +++ src/game/CObjBase.h | 1 + src/game/chars/CChar.cpp | 1 + src/game/chars/CCharNPCPet.cpp | 10 ++++++++++ src/tables/triggers.tbl | 1 + 5 files changed, 16 insertions(+) diff --git a/Changelog.txt b/Changelog.txt index eb900a6b8..034689fd8 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -3911,3 +3911,6 @@ Added: 'H' shortcut for variables to get the value as hexadecimal. CURFOLLOWER.DELUID: The same as .DEL/DELETE, just removed the pet via its UID. CURFOLLOWER.DELINDEX: Removes the pet via its id in the (cur)follower list for that owner. - Added: spells with SPELLFLAG_SUMMON now accept LOCAL.FollowerSlotsOverride in the triggers @Success and @SpellSuccess. Default value (do not override): -1. + +13-10-2024, Jhobean +- Added: @PetRelease trigger work like @petdesert and return 1 to prevent the pet from being released. diff --git a/src/game/CObjBase.h b/src/game/CObjBase.h index 7a94ef5e1..e34a42979 100644 --- a/src/game/CObjBase.h +++ b/src/game/CObjBase.h @@ -1170,6 +1170,7 @@ enum CTRIG_TYPE : short CTRIG_PayGold, // I'm going to give out money for a service (Skill Training, hiring...). CTRIG_PersonalSpace, // i just got stepped on by other char. CTRIG_PetDesert, // I'm deserting from my owner ( starving, being hit by him ...). + CTRIG_PetRelease, // I have been released by my owner. CTRIG_Profile, // someone hit the profile button for me. CTRIG_ReceiveItem, // I was just handed an item (Not yet checked if i want it). CTRIG_RegenStat, // Hits/mana/stam/food regeneration. diff --git a/src/game/chars/CChar.cpp b/src/game/chars/CChar.cpp index a4ac213d8..c1b95127a 100644 --- a/src/game/chars/CChar.cpp +++ b/src/game/chars/CChar.cpp @@ -169,6 +169,7 @@ lpctstr const CChar::sm_szTrigName[CTRIG_QTY+1] = // static "@PayGold", // I'm going to give out money for a service (Skill Training, hiring...). "@PersonalSpace", // +i just got stepped on by other char. "@PetDesert", // I just went wild again + "@PetRelease", // I just been released by my master "@Profile", // someone hit the profile button for me. "@ReceiveItem", // I was just handed an item (Not yet checked if i want it) "@RegenStat", // Regenerating any stat diff --git a/src/game/chars/CCharNPCPet.cpp b/src/game/chars/CCharNPCPet.cpp index a9ce07c0a..91e65ff6a 100644 --- a/src/game/chars/CCharNPCPet.cpp +++ b/src/game/chars/CCharNPCPet.cpp @@ -857,6 +857,16 @@ void CChar::NPC_PetRelease() if (!m_pNPC) return; + CChar* pCharOwn = NPC_PetGetOwner(); + if (!pCharOwn) + return; + + if (IsTrigUsed(TRIGGER_PETRELEASE)) + { + if (OnTrigger(CTRIG_PetRelease, pCharOwn, nullptr) == TRIGRET_RET_TRUE) + return; + } + if (IsStatFlag(STATF_CONJURED) || (m_pNPC->m_bonded && IsStatFlag(STATF_DEAD))) { Effect(EFFECT_XYZ, ITEMID_FX_TELE_VANISH, this, 10, 15); diff --git a/src/tables/triggers.tbl b/src/tables/triggers.tbl index b81dc78ff..a200f613a 100644 --- a/src/tables/triggers.tbl +++ b/src/tables/triggers.tbl @@ -156,6 +156,7 @@ ADD(PARTYREMOVE) ADD(PAYGOLD) ADD(PERSONALSPACE) ADD(PETDESERT) +ADD(PETRELEASE) ADD(PICKUP_GROUND) ADD(PICKUP_PACK) ADD(PICKUP_SELF) From 9703cefd606de51e17278ad89e108c93a5ff7067 Mon Sep 17 00:00:00 2001 From: Jhobean <51728381+Jhobean@users.noreply.github.com> Date: Mon, 14 Oct 2024 15:51:22 -0400 Subject: [PATCH 28/32] Fix Typo error on Call Stack (#1308) --- src/game/CObjBase.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/game/CObjBase.cpp b/src/game/CObjBase.cpp index cecbdb93a..7cef3e945 100644 --- a/src/game/CObjBase.cpp +++ b/src/game/CObjBase.cpp @@ -3253,7 +3253,7 @@ bool CObjBase::_CanTick(bool fParentGoingToSleep) const void CObjBase::ResendTooltip(bool fSendFull, bool fUseCache) { - ADDTOCALLSTACK("CObjBase::UpdatePropertyFlag"); + ADDTOCALLSTACK("CObjBase::ResendTooltip"); // Send tooltip packet to all nearby clients if (g_Serv.IsLoading()) From f05188948bf1dfe5da7e4ccead089e1d0e55c441 Mon Sep 17 00:00:00 2001 From: Gladie Date: Mon, 14 Oct 2024 21:52:19 +0200 Subject: [PATCH 29/32] Registration of Packet 0xBE (#1304) --- src/common/sphereproto.h | 1 + src/network/CPacketManager.cpp | 1 + src/network/receive.cpp | 11 +++++++++++ src/network/receive.h | 14 ++++++++++++++ 4 files changed, 27 insertions(+) diff --git a/src/common/sphereproto.h b/src/common/sphereproto.h index ab1a3aaed..b9bbb908e 100644 --- a/src/common/sphereproto.h +++ b/src/common/sphereproto.h @@ -139,6 +139,7 @@ enum XCMD_TYPE // XCMD_* messages are unique in both directions. XCMD_MailMsg = 0xbb, XCMD_Season = 0xbc, XCMD_ClientVersion = 0xbd, + XCMD_AssistVersion = 0xbe, XCMD_ExtData = 0xbf, // 0xC0 XCMD_EffectEx = 0xc0, diff --git a/src/network/CPacketManager.cpp b/src/network/CPacketManager.cpp index 77a7f2ca3..35986c224 100644 --- a/src/network/CPacketManager.cpp +++ b/src/network/CPacketManager.cpp @@ -82,6 +82,7 @@ void PacketManager::registerStandardPackets(void) registerPacket(XCMD_CharProfile, new PacketProfileReq()); // profile read/write request registerPacket(XCMD_MailMsg, new PacketMailMessage()); // registerPacket(XCMD_ClientVersion, new PacketClientVersion()); // client version + registerPacket(XCMD_AssistVersion, new PacketAssistVersion()); // assist version registerPacket(XCMD_ExtData, new PacketExtendedCommand()); // registerPacket(XCMD_PromptUNICODE, new PacketPromptResponseUnicode()); // prompt response (unicode) registerPacket(XCMD_ViewRange, new PacketViewRange()); // diff --git a/src/network/receive.cpp b/src/network/receive.cpp index f78aef4f0..50e36e308 100644 --- a/src/network/receive.cpp +++ b/src/network/receive.cpp @@ -2497,6 +2497,17 @@ bool PacketClientVersion::onReceive(CNetState* net) return true; } +/*************************************************************************** +* +* +* Packet 0xBD : PacketAssistVersion assist version +* +* +***************************************************************************/ +PacketAssistVersion::PacketAssistVersion() : Packet(0) +{ +} +PacketAssistVersion::~PacketAssistVersion() = default; /*************************************************************************** * diff --git a/src/network/receive.h b/src/network/receive.h index 4f7c65400..f464c8a6e 100644 --- a/src/network/receive.h +++ b/src/network/receive.h @@ -722,6 +722,20 @@ class PacketClientVersion : public Packet virtual bool onReceive(CNetState* net); }; +/*************************************************************************** + * + * + * Packet 0xBE : PacketAssistVersion assist version + * + * + ***************************************************************************/ +class PacketAssistVersion : public Packet +{ +public: + PacketAssistVersion(); + virtual ~PacketAssistVersion(); +}; + /*************************************************************************** * * From 6cabb6a568a4799674b3993dcf5719d9df249e49 Mon Sep 17 00:00:00 2001 From: Jhobean Date: Tue, 15 Oct 2024 20:14:52 -0400 Subject: [PATCH 30/32] Add trigger on tooltip --- Changelog.txt | 5 ++++- src/game/clients/CClientMsg_AOSTooltip.cpp | 18 +++++++++++++++++- src/network/send.cpp | 2 ++ 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/Changelog.txt b/Changelog.txt index d4308c216..45083454d 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -3913,12 +3913,15 @@ Added: 'H' shortcut for variables to get the value as hexadecimal. - Added: spells with SPELLFLAG_SUMMON now accept LOCAL.FollowerSlotsOverride in the triggers @Success and @SpellSuccess. Default value (do not override): -1. 13-10-2024, Jhobean +- Added: @PetRelease trigger work like @petdesert and return 1 to prevent the pet from being released. - Added: @DisplayName give possibility to change the name other player see on the paperdoll and on status bar. Could be use on RP server where unknow person don't know your name before presentation. + Since the name is use at many place, this trigger happen on 3 differents place in the source. + If you use tooltip, you must set TooltipCache=0 on ini to avoid other player see the tooltip you generate for a particular player. src.: The player requesting to view the name on the paperdoll or status i: The player stalked by the src. ARGS (R/W): The name to display + ARGN (R): Tell if trigger is launch on 1:Paperdoll 2:Status 3: Tooltip RETURN 1 : Change the name to the new value of ARGS -- Added: @PetRelease trigger work like @petdesert and return 1 to prevent the pet from being released. diff --git a/src/game/clients/CClientMsg_AOSTooltip.cpp b/src/game/clients/CClientMsg_AOSTooltip.cpp index 15d3bfc0a..e41a28527 100644 --- a/src/game/clients/CClientMsg_AOSTooltip.cpp +++ b/src/game/clients/CClientMsg_AOSTooltip.cpp @@ -35,7 +35,6 @@ bool CClient::addAOSTooltip(CObjBase * pObj, bool fRequested, bool fShop) if (PacketPropertyList::CanSendTo(GetNetState()) == false) return false; - // Enhanced and KR clients always need the tooltips (but they can't be enabled without FEATURE_AOS_UPDATE_B, since this has to be sent to the client via the packet 0xB9). // Shop items use tooltips whether they're disabled or not, // so we can just send a basic tooltip with the item name @@ -246,6 +245,22 @@ void CClient::AOSTooltip_addName(CObjBase* pObj) } else if (pChar) { + CChar* pClient = static_cast(GetChar()); + if (IsTrigUsed(TRIGGER_DISPLAYNAME) && pChar->IsClientType() && (pChar != pClient)) //Avoid launch trigger if the target is the same character + { + CScriptTriggerArgs args; + args.m_s1 = pChar->GetName(); + args.m_iN1 = 3;//Trigger use on tooltip + + if (pChar->OnTrigger(CTRIG_DisplayName, pClient, &args) == TRIGRET_RET_TRUE) + { + /*To make it work correctly TooltipCache must be set to 0 on ini or other player will use wrong tooltip*/ + /*Maybe a beter way can be done*/ + PUSH_FRONT_TOOLTIP(pChar, new CClientTooltip(1070722, args.m_s1)); // ~1_NOTHING~ + return; //Avoid to show the prefix and suffix. Show only the name you want + } + } + lpctstr lpPrefix = pChar->GetKeyStr("NAME.PREFIX"); if (!*lpPrefix) @@ -254,6 +269,7 @@ void CClient::AOSTooltip_addName(CObjBase* pObj) if (!*lpPrefix) lpPrefix = " "; + tchar * lpSuffix = Str_GetTemp(); Str_CopyLimitNull(lpSuffix, pChar->GetKeyStr("NAME.SUFFIX"), Str_TempLength()); diff --git a/src/network/send.cpp b/src/network/send.cpp index 793e0ffd1..ef069b021 100644 --- a/src/network/send.cpp +++ b/src/network/send.cpp @@ -155,6 +155,7 @@ PacketObjectStatus::PacketObjectStatus(CClient* target, CObjBase* object) : Pack { CScriptTriggerArgs args; args.m_s1 = object->GetName(); + args.m_iN1 =2;//Trigger use on status if (objectChar->OnTrigger(CTRIG_DisplayName, character, &args) == TRIGRET_RET_TRUE) { @@ -2650,6 +2651,7 @@ PacketPaperdoll::PacketPaperdoll(const CClient* target, CChar* character) : Pack { CScriptTriggerArgs args; args.m_s1 = character->GetName(); + args.m_iN1 = 1;//Trigger use on paperdoll if (character->OnTrigger(CTRIG_DisplayName, target->GetChar(), &args) == TRIGRET_RET_TRUE) { bCustomName = 1; From facf2c91079a3ef6f428a5561061b27e2f734563 Mon Sep 17 00:00:00 2001 From: Jhobean Date: Wed, 16 Oct 2024 07:25:39 -0400 Subject: [PATCH 31/32] Always new tooltips for player --- Changelog.txt | 1 - src/game/clients/CClientMsg_AOSTooltip.cpp | 9 ++++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/Changelog.txt b/Changelog.txt index 45083454d..4da42259d 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -3917,7 +3917,6 @@ Added: 'H' shortcut for variables to get the value as hexadecimal. - Added: @DisplayName give possibility to change the name other player see on the paperdoll and on status bar. Could be use on RP server where unknow person don't know your name before presentation. Since the name is use at many place, this trigger happen on 3 differents place in the source. - If you use tooltip, you must set TooltipCache=0 on ini to avoid other player see the tooltip you generate for a particular player. src.: The player requesting to view the name on the paperdoll or status i: The player stalked by the src. ARGS (R/W): The name to display diff --git a/src/game/clients/CClientMsg_AOSTooltip.cpp b/src/game/clients/CClientMsg_AOSTooltip.cpp index e41a28527..1e3bafaec 100644 --- a/src/game/clients/CClientMsg_AOSTooltip.cpp +++ b/src/game/clients/CClientMsg_AOSTooltip.cpp @@ -67,14 +67,17 @@ bool CClient::addAOSTooltip(CObjBase * pObj, bool fRequested, bool fShop) PacketPropertyList* propertyList = pObj->GetPropertyList(); - if (propertyList == nullptr || propertyList->hasExpired(g_Cfg.m_iTooltipCache)) + CItem* pItem = pObj->IsItem() ? static_cast(pObj) : nullptr; + CChar* pChar = pObj->IsChar() ? static_cast(pObj) : nullptr; + + //If pChar is a client we avoid to use cache because we always generate new tooltip for player. + if ((pChar && pChar->IsClientActive()) || propertyList == nullptr || propertyList->hasExpired(g_Cfg.m_iTooltipCache)) { pObj->m_TooltipData.clear(); pObj->FreePropertyList(); CClientTooltip* t = nullptr; - CItem *pItem = pObj->IsItem() ? static_cast(pObj) : nullptr; - CChar *pChar = pObj->IsChar() ? static_cast(pObj) : nullptr; + //DEBUG_MSG(("Preparing tooltip for 0%x (%s)\n", (dword)pObj->GetUID(), pObj->GetName())); if (fNameOnly) // if we only want to display the name From 2742ba2a480379f9ce459e17ace0c5130d32398a Mon Sep 17 00:00:00 2001 From: Jhobean Date: Sun, 10 Nov 2024 13:05:59 -0500 Subject: [PATCH 32/32] Ajout halfelin --- src/common/sphereproto.h | 5 +++-- src/game/chars/CChar.h | 1 + src/game/chars/CCharAct.cpp | 10 +++++++--- src/game/chars/CCharBase.cpp | 12 ++++++++++-- src/game/chars/CCharBase.h | 1 + src/game/chars/CCharNPCStatus.cpp | 3 +++ src/game/chars/CCharSpell.cpp | 2 ++ src/game/chars/CCharStatus.cpp | 11 ++++++++++- src/game/clients/CClientEvent.cpp | 2 +- src/game/uo_files/uofiles_enums_creid.h | 8 ++++++++ src/network/send.cpp | 6 ++++++ 11 files changed, 52 insertions(+), 9 deletions(-) diff --git a/src/common/sphereproto.h b/src/common/sphereproto.h index d03c8126b..d5952df42 100644 --- a/src/common/sphereproto.h +++ b/src/common/sphereproto.h @@ -656,8 +656,9 @@ enum RACE_TYPE // character race, used in new character creation (0x8D) and sta RACETYPE_UNDEFINED = 0x00, // none of the below RACETYPE_HUMAN = 0x01, // human RACETYPE_ELF = 0x02, // elf - RACETYPE_GARGOYLE = 0x03, // gargoyle - RACETYPE_VAMPIRE = 0x04 // vampire + RACETYPE_GARGOYLE = 0x03, // Nain + RACETYPE_VAMPIRE = 0x04, // Orc + RACETYPE_HALFELIN = 0x05 // Halfelin }; diff --git a/src/game/chars/CChar.h b/src/game/chars/CChar.h index 9b9a44947..21127eb88 100644 --- a/src/game/chars/CChar.h +++ b/src/game/chars/CChar.h @@ -394,6 +394,7 @@ public: void StatFlag_Mod(uint64 uiStatFlag, bool fMod) noexcept; bool IsElf() const; bool IsGargoyle() const; bool IsVampire() const; + bool IsHalfelin() const; int GetStatPercent(STAT_TYPE i) const; lpctstr GetTradeTitle() const; // Paperdoll title for character p (2) diff --git a/src/game/chars/CCharAct.cpp b/src/game/chars/CCharAct.cpp index e33fc925c..6f8c2d609 100644 --- a/src/game/chars/CCharAct.cpp +++ b/src/game/chars/CCharAct.cpp @@ -4441,9 +4441,13 @@ bool CChar::Death() case CREID_VAMPWOMAN: pszGhostName = ( fFemale ? "c_vamp_ghost_woman" : "c_vamp_ghost_man" ); break; - default: - pszGhostName = ( fFemale ? "c_ghost_woman" : "c_ghost_man" ); - break; + case CREID_HALFELINMAN: + case CREID_HALFELINWOMAN: + pszGhostName = (fFemale ? "c_halfelin_ghost_woman" : "c_halfelin_ghost_man"); + break; + default: + pszGhostName = (fFemale ? "c_ghost_woman" : "c_ghost_man"); + break; } ASSERT(pszGhostName != nullptr); diff --git a/src/game/chars/CCharBase.cpp b/src/game/chars/CCharBase.cpp index a8841788c..4844a2550 100644 --- a/src/game/chars/CCharBase.cpp +++ b/src/game/chars/CCharBase.cpp @@ -537,7 +537,7 @@ bool CCharBase::IsValidDispID( CREID_TYPE id ) noexcept // static bool CCharBase::IsPlayableID( CREID_TYPE id, bool bCheckGhost) noexcept { - return ( CCharBase::IsHumanID( id, bCheckGhost) || CCharBase::IsElfID( id, bCheckGhost) || CCharBase::IsGargoyleID( id, bCheckGhost) || CCharBase::IsVampireID(id, bCheckGhost)); + return ( CCharBase::IsHumanID( id, bCheckGhost) || CCharBase::IsElfID( id, bCheckGhost) || CCharBase::IsGargoyleID( id, bCheckGhost) || CCharBase::IsVampireID(id, bCheckGhost) || CCharBase::IsHalfelinID(id, bCheckGhost)); } bool CCharBase::IsHumanID( CREID_TYPE id, bool bCheckGhost ) noexcept // static @@ -570,4 +570,12 @@ bool CCharBase::IsVampireID(CREID_TYPE id, bool bCheckGhost) noexcept // static return(id == CREID_VAMPMAN || id == CREID_VAMPWOMAN || id == CREID_VAMPGHOSTMAN || id == CREID_VAMPGHOSTWOMAN); else return(id == CREID_VAMPMAN || id == CREID_VAMPWOMAN ); -} \ No newline at end of file +} + +bool CCharBase::IsHalfelinID(CREID_TYPE id, bool bCheckGhost) noexcept // static +{ + if (bCheckGhost == true) + return(id == CREID_HALFELINMAN || id == CREID_HALFELINWOMAN || id == CREID_HALFELINGHOSTMAN || id == CREID_HALFELINGHOSTWOMAN); + else + return(id == CREID_HALFELINMAN || id == CREID_HALFELINWOMAN); +} diff --git a/src/game/chars/CCharBase.h b/src/game/chars/CCharBase.h index 44fb1da28..581b34187 100644 --- a/src/game/chars/CCharBase.h +++ b/src/game/chars/CCharBase.h @@ -109,6 +109,7 @@ class CCharBase : public CBaseBaseDef // define basic info about each "TYPE" of static bool IsElfID( CREID_TYPE id, bool fCheckGhost = false) noexcept; static bool IsGargoyleID( CREID_TYPE id, bool fCheckGhost = false ) noexcept; static bool IsVampireID(CREID_TYPE id, bool fCheckGhost = false) noexcept; + static bool IsHalfelinID(CREID_TYPE id, bool fCheckGhost = false) noexcept; bool IsFemale() const noexcept { diff --git a/src/game/chars/CCharNPCStatus.cpp b/src/game/chars/CCharNPCStatus.cpp index d54ba0ba6..20b943efa 100644 --- a/src/game/chars/CCharNPCStatus.cpp +++ b/src/game/chars/CCharNPCStatus.cpp @@ -36,6 +36,9 @@ CREID_TYPE CChar::NPC_GetAllyGroupType(CREID_TYPE idTest) // static case CREID_VAMPMAN: case CREID_VAMPWOMAN: return CREID_VAMPMAN; + case CREID_HALFELINMAN: + case CREID_HALFELINWOMAN: + return CREID_HALFELINMAN; case CREID_OGRE: case CREID_OGRE_LORD: diff --git a/src/game/chars/CCharSpell.cpp b/src/game/chars/CCharSpell.cpp index 55c60c5ae..66f6313d6 100644 --- a/src/game/chars/CCharSpell.cpp +++ b/src/game/chars/CCharSpell.cpp @@ -3988,6 +3988,8 @@ bool CChar::OnSpellEffect( SPELL_TYPE spell, CChar * pCharSrc, int iSkillLevel, SetID( pCharDef->IsFemale() ? CREID_GARGMAN : CREID_GARGWOMAN ); else if (IsVampire()) SetID(pCharDef->IsFemale() ? CREID_VAMPMAN : CREID_VAMPWOMAN); + else if (IsHalfelin()) + SetID(pCharDef->IsFemale() ? CREID_HALFELINMAN : CREID_HALFELINWOMAN); _iPrev_id = GetID(); } break; diff --git a/src/game/chars/CCharStatus.cpp b/src/game/chars/CCharStatus.cpp index 837d0d139..1c7fcfdde 100644 --- a/src/game/chars/CCharStatus.cpp +++ b/src/game/chars/CCharStatus.cpp @@ -97,7 +97,7 @@ bool CChar::CanUnderstandGhost() const bool CChar::IsPlayableCharacter() const { - return( IsHuman() || IsElf() || IsGargoyle() || IsVampire()); + return( IsHuman() || IsElf() || IsGargoyle() || IsVampire() || IsHalfelin()); } bool CChar::IsHuman() const @@ -120,6 +120,11 @@ bool CChar::IsVampire() const return(CCharBase::IsVampireID(GetDispID())); } +bool CChar::IsHalfelin() const +{ + return(CCharBase::IsHalfelinID(GetDispID())); +} + CItemContainer * CChar::GetPack() const { return( dynamic_cast (LayerFind( LAYER_PACK )) ); @@ -621,6 +626,8 @@ lpctstr CChar::GetPronoun() const case CREID_GARGGHOSTMAN: case CREID_VAMPMAN: case CREID_VAMPGHOSTMAN: + case CREID_HALFELINMAN: + case CREID_HALFELINGHOSTMAN: return g_Cfg.GetDefaultMsg(DEFMSG_PRONOUN_HE); case CREID_WOMAN: case CREID_GHOSTWOMAN: @@ -630,6 +637,8 @@ lpctstr CChar::GetPronoun() const case CREID_GARGGHOSTWOMAN: case CREID_VAMPWOMAN: case CREID_VAMPGHOSTWOMAN: + case CREID_HALFELINWOMAN: + case CREID_HALFELINGHOSTWOMAN: return g_Cfg.GetDefaultMsg(DEFMSG_PRONOUN_SHE); default: return g_Cfg.GetDefaultMsg(DEFMSG_PRONOUN_IT); diff --git a/src/game/clients/CClientEvent.cpp b/src/game/clients/CClientEvent.cpp index 05b9effc2..0320e633f 100644 --- a/src/game/clients/CClientEvent.cpp +++ b/src/game/clients/CClientEvent.cpp @@ -1215,7 +1215,7 @@ void CClient::Event_VendorBuy(CChar* pVendor, const VendorItem* items, uint uiIt } case IT_BEARD: { - if ((m_pChar->GetDispID() != CREID_MAN) && (m_pChar->GetDispID() != CREID_GARGMAN) && (m_pChar->GetDispID() != CREID_VAMPMAN) && !m_pChar->IsPriv(PRIV_GM)) + if ((m_pChar->GetDispID() != CREID_MAN) && (m_pChar->GetDispID() != CREID_GARGMAN) && (m_pChar->GetDispID() != CREID_GARGWOMAN) && (m_pChar->GetDispID() != CREID_VAMPMAN) && (m_pChar->GetDispID() != CREID_HALFELINMAN) && !m_pChar->IsPriv(PRIV_GM)) { pVendor->Speak(g_Cfg.GetDefaultMsg(DEFMSG_NPC_VENDOR_CANTBUY)); return; diff --git a/src/game/uo_files/uofiles_enums_creid.h b/src/game/uo_files/uofiles_enums_creid.h index 96b86db32..af75df10f 100644 --- a/src/game/uo_files/uofiles_enums_creid.h +++ b/src/game/uo_files/uofiles_enums_creid.h @@ -387,16 +387,24 @@ enum CREID_TYPE : uint32_t // enum the creature animations. (dont allow any othe CREID_ELFGHOSTMAN = 0x25F, CREID_ELFGHOSTWOMAN = 0x260, + //Custom NAIN CREID_GARGMAN = 0x29A, // 666 decimal CREID_GARGWOMAN = 0x29B, CREID_GARGGHOSTMAN = 0x2B6, // 694 CREID_GARGGHOSTWOMAN = 0x2B7, + //Custom ORC CREID_VAMPMAN = 0x2E8, // 744 decimal CREID_VAMPWOMAN = 0x2E9, CREID_VAMPGHOSTMAN = 0x2EE, // Ghost robe is not automatic ! CREID_VAMPGHOSTWOMAN = 0x2EF, + //Custom halfelin + CREID_HALFELINMAN = 0x1A4, // 420 decimal + CREID_HALFELINWOMAN = 0x1A5, //421 + CREID_HALFELINGHOSTMAN = 0x1B8, //440 + CREID_HALFELINGHOSTWOMAN = 0x1B9, //441 + //.. CREID_MAN_PALADIN = 0x8D, diff --git a/src/network/send.cpp b/src/network/send.cpp index 9eaa693ba..993cfb494 100644 --- a/src/network/send.cpp +++ b/src/network/send.cpp @@ -275,6 +275,12 @@ void PacketObjectStatus::WriteVersionSpecific(const CClient* target, CChar* othe case CREID_VAMPGHOSTWOMAN: writeByte(RACETYPE_VAMPIRE); break; + case CREID_HALFELINMAN: + case CREID_HALFELINWOMAN: + case CREID_HALFELINGHOSTMAN: + case CREID_HALFELINGHOSTWOMAN: + writeByte(RACETYPE_HALFELIN); + break; default: writeByte(RACETYPE_UNDEFINED); break;