From 0461db7778e1e3f1701d0073f0be734a64e04179 Mon Sep 17 00:00:00 2001 From: Raylde <50953519+Raylde@users.noreply.github.com> Date: Thu, 30 Nov 2023 11:39:22 +0100 Subject: [PATCH 1/5] change the priority of mainthread from realtime to highest. --- src/game/spheresvr.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/game/spheresvr.cpp b/src/game/spheresvr.cpp index 6cf4654e3..3df3eb59c 100644 --- a/src/game/spheresvr.cpp +++ b/src/game/spheresvr.cpp @@ -159,7 +159,7 @@ extern CDataBaseAsyncHelper g_asyncHdb; // Main server loop MainThread::MainThread() - : AbstractSphereThread("T_Main", IThread::RealTime) + : AbstractSphereThread("T_Main", IThread::Highest) { m_profile.EnableProfile(PROFILE_NETWORK_RX); m_profile.EnableProfile(PROFILE_CLIENTS); @@ -805,7 +805,7 @@ int _cdecl main( int argc, char * argv[] ) if (shouldRunInThread) { g_Main.start(); // Starts another thread to do all the work (it does Sphere_OnTick()) - IThread::setThreadName("T_Monitor"); + IThread::setThreadName("SphereUO"); Sphere_MainMonitorLoop(); // Use this thread to monitor if the others are stuck } else From 7882ad05b46ba6ca9d7f3354f2aa7bce652072f6 Mon Sep 17 00:00:00 2001 From: Raylde <50953519+Raylde@users.noreply.github.com> Date: Thu, 30 Nov 2023 13:27:46 +0100 Subject: [PATCH 2/5] add _bondedTime to CharNPC to track when pet becomes bonded. Check when npc eat --- src/game/chars/CCharNPC.cpp | 10 ++++++++++ src/game/chars/CCharNPC.h | 1 + src/game/chars/CCharNPCPet.cpp | 10 ++++++++++ src/game/chars/CCharSkill.cpp | 5 +++++ src/game/chars/CCharUse.cpp | 18 ++++++++++++++++++ src/tables/CCharNpc_props.tbl | 1 + 6 files changed, 45 insertions(+) diff --git a/src/game/chars/CCharNPC.cpp b/src/game/chars/CCharNPC.cpp index 921954b00..0c9860d93 100644 --- a/src/game/chars/CCharNPC.cpp +++ b/src/game/chars/CCharNPC.cpp @@ -45,6 +45,7 @@ CCharNPC::CCharNPC( CChar * pChar, NPCBRAIN_TYPE NPCBrain ) m_Home_Dist_Wander = INT16_MAX; // as far as i want. m_Act_Motivation = 0; m_bonded = 0; + _bondedTime = 0; #ifndef _WIN32 for (int i_tmpN=0;i_tmpN < MAX_NPC_PATH_STORAGE_SIZE;i_tmpN++) { @@ -83,6 +84,9 @@ bool CCharNPC::r_LoadVal( CChar * pChar, CScript &s ) if ( !g_Serv.IsLoading() ) pChar->UpdatePropertyFlag(); break; + case CNC_BONDEDTIME: + _bondedTime = s.GetArg64Val(); + break; case CNC_FOLLOWERSLOTS: pChar->SetDefNum(s.GetKey(), s.GetArgVal(), false ); break; @@ -167,6 +171,9 @@ bool CCharNPC::r_WriteVal( CChar * pChar, lpctstr ptcKey, CSString & sVal ) case CNC_BONDED: sVal.FormatVal( m_bonded ); break; + case CNC_BONDEDTIME: + sVal.Format64Val( _bondedTime ); + break; case CNC_FOLLOWERSLOTS: sVal.FormatLLVal(pChar->GetDefNum(ptcKey, true)); break; @@ -248,6 +255,9 @@ void CCharNPC::r_WriteChar( CChar * pChar, CScript & s ) if (m_bonded) s.WriteKeyVal("BONDED", m_bonded); + if (_bondedTime) + s.WriteKeyVal("BONDEDTIME", _bondedTime); + if ( m_Need.GetResourceID().IsValidUID()) { TemporaryString tsTemp; diff --git a/src/game/chars/CCharNPC.h b/src/game/chars/CCharNPC.h index 9b8811ee4..dfc67f6e2 100644 --- a/src/game/chars/CCharNPC.h +++ b/src/game/chars/CCharNPC.h @@ -31,6 +31,7 @@ class CCharNPC word m_Home_Dist_Wander; // Distance to allow to "wander". byte m_Act_Motivation; // 0-100 (100=very greatly) how bad do i want to do the current action. bool m_bonded; // Bonded pet + int64 _bondedTime; // Time when bonded CResourceRefArray m_Speech; // Speech fragment list (other stuff we know): We respond to what we hear with this. diff --git a/src/game/chars/CCharNPCPet.cpp b/src/game/chars/CCharNPCPet.cpp index 18b68ec77..933382eb9 100644 --- a/src/game/chars/CCharNPCPet.cpp +++ b/src/game/chars/CCharNPCPet.cpp @@ -4,10 +4,13 @@ #include "../components/CCSpawn.h" #include "../items/CItemVendable.h" #include "../CServerTime.h" +#include "../CWorldGameTime.h" #include "../triggers.h" #include "CChar.h" #include "CCharNPC.h" +static int32 const BondedTime = 7 * 24 * 60 * 60 * MSECS_PER_SEC; // 7 days + void CChar::NPC_OnPetCommand( bool fSuccess, CChar * pMaster ) { ADDTOCALLSTACK("CChar::NPC_OnPetCommand"); @@ -548,6 +551,7 @@ void CChar::NPC_PetClearOwners() CChar * pOwner = NPC_PetGetOwner(); Memory_ClearTypes(MEMORY_IPET|MEMORY_FRIEND); m_pNPC->m_bonded = 0; // pets without owner cannot be bonded + m_pNPC->_bondedTime = 0; // reset bonded time if ( NPC_IsVendor() ) { @@ -614,6 +618,12 @@ bool CChar::NPC_PetSetOwner( CChar * pChar ) pBank->m_itEqBankBox.m_Check_Amount = 0; StatFlag_Set(STATF_INVUL); } + else + { + // if is a pet, set the bonded time to new owner + if (m_pNPC) + m_pNPC->_bondedTime = CWorldGameTime::GetCurrentTime().GetTimeRaw() + BondedTime; + } if ( IsSetOF(OF_PetSlots) ) { diff --git a/src/game/chars/CCharSkill.cpp b/src/game/chars/CCharSkill.cpp index cc46c1349..cd34f9bfb 100644 --- a/src/game/chars/CCharSkill.cpp +++ b/src/game/chars/CCharSkill.cpp @@ -8,6 +8,7 @@ #include "../items/CItemVendable.h" #include "../triggers.h" #include "../CServer.h" +#include "../CWorldGameTime.h" #include "../CWorldMap.h" #include "CChar.h" #include "CCharNPC.h" @@ -2305,6 +2306,10 @@ int CChar::Skill_Taming( SKTRIG_TYPE stage ) pChar->m_Act_UID = GetUID(); pChar->Skill_Start(NPCACT_FOLLOW_TARG); + // set the new bonded time for the pet + if (pChar->m_pNPC) + pChar->m_pNPC->_bondedTime = CWorldGameTime::GetCurrentTime().GetTimeRaw(); + if (fTamedPrev) return -SKTRIG_QTY; // no credit for this. diff --git a/src/game/chars/CCharUse.cpp b/src/game/chars/CCharUse.cpp index b69414716..d1f2d4fbe 100644 --- a/src/game/chars/CCharUse.cpp +++ b/src/game/chars/CCharUse.cpp @@ -905,6 +905,24 @@ void CChar::Use_EatQty( CItem * pFood, ushort uiQty ) UpdateDir(pFood); EatAnim(pFood->GetName(), uiRestore * uiQty); pFood->ConsumeAmount(uiQty); + + //check bondet time to bond + if (m_pNPC && m_pNPC->_bondedTime && m_pNPC->_bondedTime < CWorldGameTime::GetCurrentTime().GetTimeRaw()) + { + //only if have owner + const CChar * pOwner = NPC_PetGetOwner(); + if (pOwner) + { + m_pNPC->_bondedTime = 0; + m_pNPC->m_bonded = true; + UpdatePropertyFlag(); + const CClient* pClient = pOwner->GetClientActive(); + if (pClient) + { + pClient->addBarkLocalized(1049666, nullptr); // Your pet has bonded with you! + } + } + } } bool CChar::Use_Eat( CItem * pItemFood, ushort uiQty ) diff --git a/src/tables/CCharNpc_props.tbl b/src/tables/CCharNpc_props.tbl index fec8c230c..c377277e5 100644 --- a/src/tables/CCharNpc_props.tbl +++ b/src/tables/CCharNpc_props.tbl @@ -6,6 +6,7 @@ ADD(ACTPRI, "ACTPRI") ADD(BONDED, "BONDED") +ADD(BONDEDTIME, "BONDEDTIME") ADD(FOLLOWERSLOTS, "FOLLOWERSLOTS") ADD(HOMEDIST, "HOMEDIST") ADD(NEED, "NEED") From 10414adebbdacb904a1c753d64bc689839d9d278 Mon Sep 17 00:00:00 2001 From: Raylde <50953519+Raylde@users.noreply.github.com> Date: Thu, 30 Nov 2023 14:07:22 +0100 Subject: [PATCH 3/5] Remove FreezeRestartTime --- src/game/CServerConfig.cpp | 9 --------- src/game/CServerConfig.h | 1 - src/game/spheresvr.cpp | 30 +++++++----------------------- 3 files changed, 7 insertions(+), 33 deletions(-) diff --git a/src/game/CServerConfig.cpp b/src/game/CServerConfig.cpp index c80140137..499b5e5d9 100644 --- a/src/game/CServerConfig.cpp +++ b/src/game/CServerConfig.cpp @@ -47,7 +47,6 @@ CServerConfig::CServerConfig() m_iDebugFlags = 0; //DEBUGF_NPC_EMOTE m_fSecure = true; - m_iFreezeRestartTime = 60; m_bAgree = false; m_fMd5Passwords = false; @@ -540,7 +539,6 @@ enum RC_TYPE RC_FEATURESTOL, RC_FLIPDROPPEDITEMS, // m_fFlipDroppedItems RC_FORCEGARBAGECOLLECT, // m_fSaveGarbageCollect - RC_FREEZERESTARTTIME, // m_iFreezeRestartTime RC_GAMEMINUTELENGTH, // m_iGameMinuteLength RC_GENERICSOUNDS, // m_fGenericSounds RC_GUARDLINGER, // m_iGuardLingerTime @@ -812,7 +810,6 @@ const CAssocReg CServerConfig::sm_szLoadKeys[RC_QTY+1] { "FEATURETOL", { ELEM_INT, static_castOFFSETOF(CServerConfig,m_iFeatureTOL) }}, { "FLIPDROPPEDITEMS", { ELEM_BOOL, static_castOFFSETOF(CServerConfig,m_fFlipDroppedItems) }}, { "FORCEGARBAGECOLLECT", { ELEM_BOOL, static_castOFFSETOF(CServerConfig,m_fSaveGarbageCollect) }}, - { "FREEZERESTARTTIME", { ELEM_INT, static_castOFFSETOF(CServerConfig,m_iFreezeRestartTime) }}, { "GAMEMINUTELENGTH", { ELEM_INT, static_castOFFSETOF(CServerConfig,m_iGameMinuteLength) }}, { "GENERICSOUNDS", { ELEM_BOOL, static_castOFFSETOF(CServerConfig,m_fGenericSounds) }}, { "GUARDLINGER", { ELEM_INT, static_castOFFSETOF(CServerConfig,m_iGuardLingerTime) }}, @@ -1202,9 +1199,6 @@ bool CServerConfig::r_LoadVal( CScript &s ) case RC_DECAYTIMER: m_iDecay_Item = s.GetArgLLVal() * 60 * MSECS_PER_SEC; break; - case RC_FREEZERESTARTTIME: - m_iFreezeRestartTime = s.GetArgLLVal() * MSECS_PER_SEC; - break; case RC_GAMEMINUTELENGTH: m_iGameMinuteLength = s.GetArgLLVal() * MSECS_PER_SEC; break; @@ -2016,9 +2010,6 @@ bool CServerConfig::r_WriteVal( lpctstr ptcKey, CSString & sVal, CTextConsole * case RC_DECAYTIMER: sVal.FormatLLVal( m_iDecay_Item / (60*MSECS_PER_SEC)); break; - case RC_FREEZERESTARTTIME: - sVal.FormatLLVal(m_iFreezeRestartTime / MSECS_PER_SEC); - break; case RC_GAMEMINUTELENGTH: sVal.FormatLLVal(m_iGameMinuteLength / MSECS_PER_SEC); break; diff --git a/src/game/CServerConfig.h b/src/game/CServerConfig.h index 8fba2cb50..d83045560 100644 --- a/src/game/CServerConfig.h +++ b/src/game/CServerConfig.h @@ -243,7 +243,6 @@ extern class CServerConfig : public CResourceHolder CSString m_sAcctBaseDir; // Where do the account files go/come from ? bool m_fSecure; // Secure mode. (will trap exceptions) - int64 m_iFreezeRestartTime; // # seconds before restarting. #define DEBUGF_NPC_EMOTE 0x0001 // NPCs emote their actions. #define DEBUGF_ADVANCE_STATS 0x0002 // prints stat % skill changes (only for _DEBUG builds). #define DEBUGF_EXP 0x0200 // experience gain/loss. diff --git a/src/game/spheresvr.cpp b/src/game/spheresvr.cpp index 3df3eb59c..1ddbd4cbf 100644 --- a/src/game/spheresvr.cpp +++ b/src/game/spheresvr.cpp @@ -416,6 +416,8 @@ int Sphere_OnTick() static void Sphere_MainMonitorLoop() { + const static byte iFreezeRestartTime = 60; // How often to check for freeze ups. (seconds) + constexpr const char *m_sClassName = "SphereMonitor"; // Just make sure the main loop is alive every so often. // This should be the parent thread. try to restart it if it is not. @@ -423,16 +425,9 @@ static void Sphere_MainMonitorLoop() { EXC_TRY("MainMonitorLoop"); - if ( g_Cfg.m_iFreezeRestartTime <= 0 ) - { - DEBUG_ERR(("Freeze Restart Time cannot be cleared at run time\n")); - g_Cfg.m_iFreezeRestartTime = 10; - } - EXC_SET_BLOCK("Sleep"); // only sleep 1 second at a time, to avoid getting stuck here when closing - // down with large m_iFreezeRestartTime values set - for (int i = 0; i < g_Cfg.m_iFreezeRestartTime; ++i) + for (int i = 0; i < iFreezeRestartTime; ++i) { if ( g_Serv.GetExitFlag() ) break; @@ -452,7 +447,6 @@ static void Sphere_MainMonitorLoop() #endif EXC_CATCH; } - } @@ -801,20 +795,10 @@ int _cdecl main( int argc, char * argv[] ) // an instance of CNetworkInput nad CNetworkOutput, which support working in a multi threaded way (declarations and definitions in network_multithreaded.h/.cpp) g_NetworkManager.start(); - const bool shouldRunInThread = ( g_Cfg.m_iFreezeRestartTime > 0 ); - if (shouldRunInThread) - { - g_Main.start(); // Starts another thread to do all the work (it does Sphere_OnTick()) - IThread::setThreadName("SphereUO"); - Sphere_MainMonitorLoop(); // Use this thread to monitor if the others are stuck - } - else - { - while ( !g_Serv.GetExitFlag() ) - { - g_Main.tick(); // Use this thread to do all the work, without monitoring the other threads state - } - } + // Starts another thread to do all the work (it does Sphere_OnTick()) + g_Main.start(); + IThread::setThreadName("SphereUO"); + Sphere_MainMonitorLoop(); // Use this thread to monitor if the others are stuck } exit_server: From 23b9cc5e3324c122cc899e7221f08a06e495ac99 Mon Sep 17 00:00:00 2001 From: Raylde <50953519+Raylde@users.noreply.github.com> Date: Thu, 30 Nov 2023 14:31:22 +0100 Subject: [PATCH 4/5] Remove MySQLticks. Now if MySql is enabled, sphere dont start if mysql cannot connect to db --- src/game/CServer.cpp | 2 +- src/game/CServerConfig.cpp | 3 --- src/game/CServerConfig.h | 1 - src/game/CWorld.cpp | 1 - src/game/CWorld.h | 3 +-- src/sphere.dic | 1 - src/sphere.ini | 3 --- 7 files changed, 2 insertions(+), 12 deletions(-) diff --git a/src/game/CServer.cpp b/src/game/CServer.cpp index d3c705279..bdb9e7a8a 100644 --- a/src/game/CServer.cpp +++ b/src/game/CServer.cpp @@ -2280,7 +2280,7 @@ nowinsock: g_Log.Event(LOGL_FATAL|LOGM_INIT, "Winsock 1.1 not found!\n"); g_Log.Event(LOGM_INIT, wSockInfo); #endif - if (g_Cfg.m_bMySql && g_Cfg.m_bMySqlTicks) + if (g_Cfg.m_bMySql) { EXC_SET_BLOCK( "Connecting to MySQL server" ); if (_hDb.Connect()) diff --git a/src/game/CServerConfig.cpp b/src/game/CServerConfig.cpp index 499b5e5d9..aefccc10d 100644 --- a/src/game/CServerConfig.cpp +++ b/src/game/CServerConfig.cpp @@ -247,7 +247,6 @@ CServerConfig::CServerConfig() // MySQL support m_bMySql = false; - m_bMySqlTicks = false; m_bAutoResDisp = true; m_iAutoPrivFlags = 0; @@ -607,7 +606,6 @@ enum RC_TYPE RC_MYSQLDB, // m_sMySqlDatabase RC_MYSQLHOST, // m_sMySqlHost RC_MYSQLPASS, // m_sMySqlPassword - RC_MYSQLTICKS, // m_bMySqlTicks RC_MYSQLUSER, // m_sMySqlUser RC_NETTTL, // m_iNetHistoryTTL RC_NETWORKTHREADPRIORITY, // _uiNetworkThreadPriority @@ -878,7 +876,6 @@ const CAssocReg CServerConfig::sm_szLoadKeys[RC_QTY+1] { "MYSQLDATABASE", { ELEM_CSTRING, static_castOFFSETOF(CServerConfig,m_sMySqlDB) }}, { "MYSQLHOST", { ELEM_CSTRING, static_castOFFSETOF(CServerConfig,m_sMySqlHost) }}, { "MYSQLPASSWORD", { ELEM_CSTRING, static_castOFFSETOF(CServerConfig,m_sMySqlPass) }}, - { "MYSQLTICKS", { ELEM_BOOL, static_castOFFSETOF(CServerConfig,m_bMySqlTicks) }}, { "MYSQLUSER", { ELEM_CSTRING, static_castOFFSETOF(CServerConfig,m_sMySqlUser) }}, { "NETTTL", { ELEM_INT, static_castOFFSETOF(CServerConfig,m_iNetHistoryTTL) }}, { "NETWORKTHREADPRIORITY", { ELEM_MASK_INT,static_castOFFSETOF(CServerConfig,_uiNetworkThreadPriority)}}, diff --git a/src/game/CServerConfig.h b/src/game/CServerConfig.h index d83045560..a89c80900 100644 --- a/src/game/CServerConfig.h +++ b/src/game/CServerConfig.h @@ -544,7 +544,6 @@ extern class CServerConfig : public CResourceHolder // MySQL features bool m_bMySql; // Enables MySQL. - bool m_bMySqlTicks; // Enables ticks from MySQL. CSString m_sMySqlHost; // MySQL Host. CSString m_sMySqlUser; // MySQL User. CSString m_sMySqlPass; // MySQL Password. diff --git a/src/game/CWorld.cpp b/src/game/CWorld.cpp index 7334772eb..fd0ca8c78 100644 --- a/src/game/CWorld.cpp +++ b/src/game/CWorld.cpp @@ -633,7 +633,6 @@ CWorld::CWorld() : _Ticker(&_GameClock) { _iTimeLastWorldSave = 0; - m_ticksWithoutMySQL = 0; m_iSaveCountID = 0; _iSaveStage = 0; _iSaveTimer = 0; diff --git a/src/game/CWorld.h b/src/game/CWorld.h index 7f06e945d..47f30e6d9 100644 --- a/src/game/CWorld.h +++ b/src/game/CWorld.h @@ -146,8 +146,7 @@ extern class CWorld : public CScriptObj, public CWorldThread int64 _iTimeLastWorldSave; // when to auto do the worldsave ? int64 _iTimeLastDeadRespawn; // when to res dead NPC's ? int64 _iTimeLastCallUserFunc; // when to call next user func - ullong m_ticksWithoutMySQL; // MySQL should be running constantly if MySQLTicks is true, keep here record of how much ticks since Sphere is not connected. - + int _iSaveStage; // Current stage of the background save. llong _iSaveTimer; // Time it takes to save diff --git a/src/sphere.dic b/src/sphere.dic index 804dabfb8..a2adf7c1c 100644 --- a/src/sphere.dic +++ b/src/sphere.dic @@ -38,7 +38,6 @@ firstconnectdate firstip flipdroppeditems forcegarbagecollect -freezerestarttime gameminutelength guardlinger guardsinstantkill diff --git a/src/sphere.ini b/src/sphere.ini index 39f38577a..8f4a65b71 100644 --- a/src/sphere.ini +++ b/src/sphere.ini @@ -941,9 +941,6 @@ MapCacheTime=120 // Always force a full garbage collection on save ForceGarbageCollect=1 -// Time before restarting when server appears hung (in seconds) -FreezeRestartTime=60 - // Limit the number of cycles the while/for loop can proceed. Setting this to // zero disables the limitation MaxLoopTimes=10000 From e15644984595308f62d61130466b970fb03e011e Mon Sep 17 00:00:00 2001 From: Raylde <50953519+Raylde@users.noreply.github.com> Date: Thu, 30 Nov 2023 14:32:01 +0100 Subject: [PATCH 5/5] move changelog to docs folder --- Changelog.txt => docs/Changelog.txt | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename Changelog.txt => docs/Changelog.txt (100%) diff --git a/Changelog.txt b/docs/Changelog.txt similarity index 100% rename from Changelog.txt rename to docs/Changelog.txt