diff --git a/Changelog.txt b/Changelog.txt index 034689fd8..8fe34af15 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -3914,3 +3914,73 @@ Added: 'H' shortcut for variables to get the value as hexadecimal. 13-10-2024, Jhobean - Added: @PetRelease trigger work like @petdesert and return 1 to prevent the pet from being released. + +25-10-2024, canerksk +- Added: Added more server function + + [PLEVEL 7] + f_onserver_mode + + f_onserver_resync_start + f_onserver_resync_restart + f_onserver_resync_failed + f_onserver_resync_success + f_onserver_resync_finish + + f_onserver_save_stage + f_onserver_save_force + f_onserver_save_try + + [FUNCTION f_onserver_mode] + // It is triggered when the server changes mode in any way, for example, saving, resyncing, loading, closing, etc. + // Variables: + // ARGN1 (R) = Server modes; + // RestockAll = 0 + // GarbageCollection = 1 + // Saving = 2 + // Running = 3 + // ResyncPause = 4 + // PreLoadingINI = 5 + // Loading = 6 + // ResyncLoad = 7 + // Exiting = 8 + + [FUNCTION f_onserver_resync_start] + // Triggered when resync starts. + // Variables: + // ARGN1 (R) = Resync Paused + // ARGN2 (R/W) = Broadcast message, 1(true) = with broadcast, 0(false) = without broadcast + + [FUNCTION f_onserver_resync_restart] + // Triggered when resync re-starts. (Only trig) + + [FUNCTION f_onserver_resync_failed] + // Triggered when resync failed. + // Variables: + // ARGN1 (R/W) = Broadcast message, 1(true) = with broadcast, 0(false) = without broadcast + + [FUNCTION f_onserver_resync_success] + // Triggered when resync success. + // Variables: + // ARGN1 (R/W) = Broadcast message, 1(true) = with broadcast, 0(false) = without broadcast + + [FUNCTION f_onserver_resync_finish] + // Triggered when resync finished. + // Variables: + // ARGN1 (R) = Is paused status + + [FUNCTION f_onserver_save_stage] + // Triggered when save mode changes + // Variables: + // ARGN1 (R) = save stage num + + [FUNCTION f_onserver_save_force] + // Triggered when save force mode + // Variables: + // ARGN1 (R) = save stage + // ARGN2 (R) = save stage num + + [FUNCTION f_onserver_save_try] + // Variables: + // ARGN1 (R) = Force Immediate + // ARGN2 (R) = Save Timer \ No newline at end of file diff --git a/src/game/CServer.cpp b/src/game/CServer.cpp index 007c9890d..21765fb36 100644 --- a/src/game/CServer.cpp +++ b/src/game/CServer.cpp @@ -433,6 +433,10 @@ void CServer::SetServerMode( SERVMODE_TYPE mode ) { ADDTOCALLSTACK("CServer::SetServerMode"); m_iModeCode.store(mode, std::memory_order_release); + + CScriptTriggerArgs Args(mode); + g_Serv.r_Call("f_onserver_mode", &g_Serv, &Args); + #ifdef _WIN32 g_NTWindow.SetWindowTitle(); #endif @@ -2394,40 +2398,62 @@ void CServer::SetResyncPause(bool fPause, CTextConsole * pSrc, bool fMessage) if ( fPause ) { m_fResyncPause = true; - g_Log.Event(LOGL_EVENT, "%s\n", g_Cfg.GetDefaultMsg(DEFMSG_SERVER_RESYNC_START)); + g_Log.Event(LOGL_EVENT, "%s\n", g_Cfg.GetDefaultMsg(DEFMSG_SERVER_RESYNC_START)); // Only console log message + + CScriptTriggerArgs args; + args.m_iN1 = m_fResyncPause ? 1 : 0; + args.m_iN2 = fMessage ? 1 : 0; + g_Serv.r_Call("f_onserver_resync_start", &g_Serv, &args); + fMessage = args.m_iN2 == 1 ? true : false; if ( fMessage ) - CWorldComm::Broadcast(g_Cfg.GetDefaultMsg(DEFMSG_SERVER_RESYNC_START)); + CWorldComm::Broadcast(g_Cfg.GetDefaultMsg(DEFMSG_SERVER_RESYNC_START)); // World broadcast message else if ( pSrc && pSrc->GetChar() ) - pSrc->SysMessage(g_Cfg.GetDefaultMsg(DEFMSG_SERVER_RESYNC_START)); + pSrc->SysMessage(g_Cfg.GetDefaultMsg(DEFMSG_SERVER_RESYNC_START)); // Only character message g_Cfg.Unload(true); SetServerMode(SERVMODE_ResyncPause); } else { - g_Log.Event(LOGL_EVENT, "%s\n", g_Cfg.GetDefaultMsg(DEFMSG_SERVER_RESYNC_RESTART)); + g_Log.Event(LOGL_EVENT, "%s\n", g_Cfg.GetDefaultMsg(DEFMSG_SERVER_RESYNC_RESTART)); // Only console log message SetServerMode(SERVMODE_ResyncLoad); + g_Serv.r_Call("f_onserver_resync_restart", &g_Serv, nullptr); if ( !g_Cfg.Load(true) ) { - g_Log.EventError("%s\n", g_Cfg.GetDefaultMsg(DEFMSG_SERVER_RESYNC_FAILED)); - if ( fMessage ) - CWorldComm::Broadcast(g_Cfg.GetDefaultMsg(DEFMSG_SERVER_RESYNC_FAILED)); + g_Log.EventError("%s\n", g_Cfg.GetDefaultMsg(DEFMSG_SERVER_RESYNC_FAILED)); // Only console log message + + CScriptTriggerArgs args; + args.m_iN1 = fMessage ? 1 : 0; + g_Serv.r_Call("f_onserver_resync_failed", &g_Serv, &args); + fMessage = args.m_iN1 == 1 ? true : false; + + if ( fMessage ) + CWorldComm::Broadcast(g_Cfg.GetDefaultMsg(DEFMSG_SERVER_RESYNC_FAILED)); // World broadcast message else if ( pSrc && pSrc->GetChar() ) - pSrc->SysMessage(g_Cfg.GetDefaultMsg(DEFMSG_SERVER_RESYNC_FAILED)); + pSrc->SysMessage(g_Cfg.GetDefaultMsg(DEFMSG_SERVER_RESYNC_FAILED)); // Only character message } else { - g_Log.Event(LOGL_EVENT, "%s\n", g_Cfg.GetDefaultMsg(DEFMSG_SERVER_RESYNC_SUCCESS)); + CScriptTriggerArgs args; + args.m_iN1 = fMessage ? 1 : 0; + g_Serv.r_Call("f_onserver_resync_success", &g_Serv, &args); + fMessage = args.m_iN1 == 1 ? true : false; + + g_Log.Event(LOGL_EVENT, "%s\n", g_Cfg.GetDefaultMsg(DEFMSG_SERVER_RESYNC_SUCCESS)); // Only console log message if ( fMessage ) - CWorldComm::Broadcast(g_Cfg.GetDefaultMsg(DEFMSG_SERVER_RESYNC_SUCCESS)); + CWorldComm::Broadcast(g_Cfg.GetDefaultMsg(DEFMSG_SERVER_RESYNC_SUCCESS)); // World broadcast message else if ( pSrc && pSrc->GetChar() ) - pSrc->SysMessage(g_Cfg.GetDefaultMsg(DEFMSG_SERVER_RESYNC_SUCCESS)); + pSrc->SysMessage(g_Cfg.GetDefaultMsg(DEFMSG_SERVER_RESYNC_SUCCESS)); // Only character message } m_fResyncPause = false; + CScriptTriggerArgs args; + args.m_iN1 = m_fResyncPause ? 1 : 0; + g_Serv.r_Call("f_onserver_resync_finish", &g_Serv, &args); + g_World.SyncGameTime(); SetServerMode(SERVMODE_Run); diff --git a/src/game/CWorld.cpp b/src/game/CWorld.cpp index df69a4ad9..216d17159 100644 --- a/src/game/CWorld.cpp +++ b/src/game/CWorld.cpp @@ -926,6 +926,10 @@ bool CWorld::SaveStage() // Save world state in stages. EXC_DEBUG_END; ++_iSaveStage; // to avoid loops, we need to skip the current operation in world save + + CScriptTriggerArgs SaveStageArgs(_iSaveStage); + g_Serv.r_Call("f_onserver_save_stage", &g_Serv, &SaveStageArgs); + return false; } @@ -992,6 +996,9 @@ bool CWorld::SaveForce() // Save world state fSuccess = false; } + CScriptTriggerArgs Args(fSave, _iSaveStage); + g_Serv.r_Call("f_onserver_save_force", &g_Serv, &Args); + g_Serv.SetServerMode(SERVMODE_Run); // Game is up and running return fSuccess; } @@ -1023,6 +1030,9 @@ bool CWorld::SaveTry( bool fForceImmediate ) // Save world state TIME_PROFILE_START; _iSaveTimer = llTicksStart; + CScriptTriggerArgs SaveTryArgs(fForceImmediate, _iSaveTimer); + g_Serv.r_Call("f_onserver_save_try", &g_Serv, &SaveTryArgs); + // Determine the save name based on the time. // exponentially degrade the saves over time. if ( ! OpenScriptBackup( m_FileData, g_Cfg.m_sWorldBaseDir, "data", m_iSaveCountID )) diff --git a/src/game/spheresvr.cpp b/src/game/spheresvr.cpp index 6f7fdeb5a..8cd9e5354 100644 --- a/src/game/spheresvr.cpp +++ b/src/game/spheresvr.cpp @@ -20,6 +20,7 @@ #include "../common/CException.h" #include "../common/CExpression.h" #include "../common/CUOInstall.h" +#include "../common/CScriptTriggerArgs.h" #include "../common/sphereversion.h" #include "../network/CNetworkManager.h" #include "../network/PingServer.h" @@ -370,6 +371,12 @@ void Sphere_ExitServer() default: ptcReason = "Server shutdown complete"; break; } + CScriptTriggerArgs ExitArgs; + ExitArgs.m_VarsLocal.SetStrNew("Reason", ptcReason); + ExitArgs.m_VarsLocal.SetNum("Flag", iExitFlag); + g_Serv.r_Call("f_onserver_exit_later", &g_Serv, &ExitArgs); + + g_Log.Event(LOGM_INIT|LOGL_FATAL, "Server terminated: %s (code %d)\n", ptcReason, iExitFlag); #ifdef _WIN32 if (!g_Serv._fCloseNTWindowOnTerminate)