From c6fe3430644a98fdb76bc1f448deb3dd128c41a7 Mon Sep 17 00:00:00 2001 From: Alexander Akulich Date: Sat, 14 Aug 2021 16:04:21 +0300 Subject: [PATCH] Reimplement ChangeLog --- src/engine/shared/config_variables.h | 2 + src/game/server/gamecontext.cpp | 140 ++++++++++++++++++++++++++- src/game/server/gamecontext.h | 8 ++ 3 files changed, 145 insertions(+), 5 deletions(-) diff --git a/src/engine/shared/config_variables.h b/src/engine/shared/config_variables.h index ef27d348b..86e91ddba 100644 --- a/src/engine/shared/config_variables.h +++ b/src/engine/shared/config_variables.h @@ -191,6 +191,8 @@ MACRO_CONFIG_INT(SvVoteDelay, sv_vote_delay, 3, 0, 9999, CFGFLAG_SERVER, "The ti MACRO_CONFIG_INT(SvFilterChatCommands, sv_filter_chat_commands, 0, 0, 1, CFGFLAG_SERVER, "Omit from the chat messages starting with ! (like !me and !best)") MACRO_CONFIG_STR(SvResetFile, sv_reset_file, 128, "reset.cfg", CFGFLAG_SERVER, "File to execute on map change or reload to set the default server settings") +MACRO_CONFIG_STR(SvChangeLogFile, sv_changelog_file, 128, "ChangeLog.txt", CFGFLAG_SERVER, "File with changelog entities") +MACRO_CONFIG_INT(SvChangeLogMaxLinesPerPage, sv_changelog_lines_page, 6, 1, 64, CFGFLAG_SERVER, "File with changelog entities") //Add cheat versions MACRO_CONFIG_STR(SvBannedVersions, sv_banned_versions, 128, "", CFGFLAG_SERVER, "Comma separated list of banned clients to be kicked on join") diff --git a/src/game/server/gamecontext.cpp b/src/game/server/gamecontext.cpp index 699b15b18..e0a8c5a88 100644 --- a/src/game/server/gamecontext.cpp +++ b/src/game/server/gamecontext.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include "gamecontext.h" #include #include @@ -32,6 +33,8 @@ enum /* INFECTION MODIFICATION START ***************************************/ bool CGameContext::m_ClientMuted[MAX_CLIENTS][MAX_CLIENTS]; +array_on_stack CGameContext::m_aChangeLogEntries; +array_on_stack CGameContext::m_aChangeLogPageIndices; void CGameContext::OnSetAuthed(int ClientID, int Level) { @@ -605,6 +608,90 @@ void CGameContext::SetClientLanguage(int ClientID, const char *pLanguage) } } +void CGameContext::InitChangelog() +{ + if(m_aChangeLogEntries.IsEmpty()) + { + ReloadChangelog(); + } +} + +void CGameContext::ReloadChangelog() +{ + for(string & Entry : m_aChangeLogEntries) + { + Entry = nullptr; + } + m_aChangeLogEntries.Clear(); + m_aChangeLogPageIndices.Clear(); + + const char *pChangelogFilename = Config()->m_SvChangeLogFile; + if(!pChangelogFilename || pChangelogFilename[0] == 0) + { + dbg_msg("ChangeLog", "ChangeLog file is not set"); + return; + } + + IOHANDLE File = Storage()->OpenFile(pChangelogFilename, IOFLAG_READ, IStorage::TYPE_ALL); + if(!File) + { + dbg_msg("ChangeLog", "unable to open '%s'", pChangelogFilename); + return; + } + + CLineReader LineReader; + LineReader.Init(File); + char *pLine = nullptr; + const int MaxLinesPerPage = Config()->m_SvChangeLogMaxLinesPerPage; + int AddedLines = 0; + + array_on_stack SamePageItemStartChars = { + ' ', + '-', + }; + + while((pLine = LineReader.Get())) + { + if(pLine[0] == 0) + continue; + + bool ThisLineIsPartOfPrevious = pLine[0] == ' '; + bool ImplicitNewPage = str_comp(pLine, "") == 0; + bool ExplicitNewPage = m_aChangeLogPageIndices.IsEmpty() || (AddedLines >= MaxLinesPerPage); + ExplicitNewPage = ExplicitNewPage || !SamePageItemStartChars.Contains(pLine[0]); + if(ImplicitNewPage || ExplicitNewPage) + { + if(m_aChangeLogPageIndices.Size() == m_aChangeLogPageIndices.Capacity()) + { + dbg_msg("ChangeLog", "ChangeLog truncated: only %d pages allowed", m_aChangeLogPageIndices.Capacity()); + break; + } + if(ThisLineIsPartOfPrevious && !m_aChangeLogEntries.IsEmpty()) + { + m_aChangeLogPageIndices.Add(m_aChangeLogEntries.Size() - 1); + } + else + { + m_aChangeLogPageIndices.Add(m_aChangeLogEntries.Size()); + } + AddedLines = 0; + } + if(ImplicitNewPage) + { + continue; + } + + if(m_aChangeLogEntries.Size() == m_aChangeLogEntries.Capacity()) + { + dbg_msg("ChangeLog", "ChangeLog truncated: only %d lines allowed", m_aChangeLogEntries.Capacity()); + break; + } + m_aChangeLogEntries.Add(pLine); + ++AddedLines; + } + io_close(File); +} + void CGameContext::SendBroadcast(int To, const char *pText, int Priority, int LifeSpan) { int Start = (To < 0 ? 0 : To); @@ -4072,15 +4159,55 @@ bool CGameContext::ConChangeLog(IConsole::IResult *pResult) { int ClientID = pResult->GetClientID(); - int Page = pResult->GetInteger(0); - Page = 0; + if(m_aChangeLogEntries.Size() == 0) + { + SendChatTarget_Localization(ClientID, CHATCATEGORY_DEFAULT, _("ChangeLog is not provided"), nullptr); + return true; + } - if(1) + int PageNumber = pResult->GetInteger(0); + if(PageNumber <= 0) { - SendChatTarget_Localization(ClientID, CHATCATEGORY_DEFAULT, _("ChangeLog is not available"), nullptr); + PageNumber = 1; + } + int PagesInTotal = m_aChangeLogPageIndices.Size(); + if(PageNumber > PagesInTotal) + { + SendChatTarget_Localization(ClientID, CHATCATEGORY_DEFAULT, _("ChangeLog page {int:PageNumber} is not available"), + "PageNumber", &PageNumber, + nullptr); return true; } + int PageIndex = PageNumber - 1; + int From = m_aChangeLogPageIndices.At(PageIndex); + int To = (PageIndex + 1) < m_aChangeLogPageIndices.Size() ? m_aChangeLogPageIndices.At(PageIndex + 1) : m_aChangeLogEntries.Size(); + + for(int i = From; i < To; ++i) + { + const char *pText = m_aChangeLogEntries.At(i); + SendChatTarget(ClientID, pText); + } + + if(PageNumber != PagesInTotal) + { + int NextPage = PageNumber + 1; + + SendChatTarget_Localization(ClientID, CHATCATEGORY_DEFAULT, + _("(page {int:PageNumber}/{int:PagesInTotal}, see /changelog {int:NextPage})"), + "PageNumber", &PageNumber, + "PagesInTotal", &PagesInTotal, + "NextPage", &NextPage, + nullptr); + } + + return true; +} + +bool CGameContext::ConReloadChangeLog(IConsole::IResult *pResult, void *pUserData) +{ + CGameContext *pSelf = (CGameContext *)pUserData; + pSelf->ReloadChangelog(); return true; } @@ -4185,7 +4312,8 @@ void CGameContext::OnConsoleInit() Console()->Register("stats", "i", CFGFLAG_CHAT|CFGFLAG_USER, ConStats, this, "Show stats by id"); #endif Console()->Register("help", "?s", CFGFLAG_CHAT|CFGFLAG_USER, ConHelp, this, "Display help"); - Console()->Register("changelog", "?i", CFGFLAG_CHAT|CFGFLAG_USER, ConChangeLog, this, "Display changelogs"); + Console()->Register("reload_changelog", "?i", CFGFLAG_SERVER, ConReloadChangeLog, this, "Reload the changelog file"); + Console()->Register("changelog", "?i", CFGFLAG_CHAT|CFGFLAG_USER, ConChangeLog, this, "Display a changelog page"); Console()->Register("customskin", "s", CFGFLAG_CHAT|CFGFLAG_USER, ConCustomSkin, this, "Display information about the mod"); Console()->Register("alwaysrandom", "i<0|1>", CFGFLAG_CHAT|CFGFLAG_USER, ConAlwaysRandom, this, "Display information about the mod"); Console()->Register("antiping", "i<0|1>", CFGFLAG_CHAT|CFGFLAG_USER, ConAntiPing, this, "Try to improve your ping"); @@ -4296,6 +4424,8 @@ void CGameContext::OnInit(/*class IKernel *pKernel*/) } } #endif + + InitChangelog(); } void CGameContext::OnStartRound() diff --git a/src/game/server/gamecontext.h b/src/game/server/gamecontext.h index da44eb2cd..c901de83e 100644 --- a/src/game/server/gamecontext.h +++ b/src/game/server/gamecontext.h @@ -3,6 +3,9 @@ #ifndef GAME_SERVER_GAMECONTEXT_H #define GAME_SERVER_GAMECONTEXT_H +#include +#include + #include #include #include @@ -275,6 +278,7 @@ class CGameContext : public IGameServer static bool ConCmdList(IConsole::IResult *pResult, void *pUserData); static bool ConChangeLog(IConsole::IResult *pResult, void *pUserData); bool ConChangeLog(IConsole::IResult *pResult); + static bool ConReloadChangeLog(IConsole::IResult *pResult, void *pUserData); static bool ConClearFunRounds(IConsole::IResult *pResult, void *pUserData); static bool ConAddFunRound(IConsole::IResult *pResult, void *pUserData); @@ -323,12 +327,16 @@ class CGameContext : public IGameServer void SendScoreSound(int ClientID); void AddBroadcast(int ClientID, const char* pText, int Priority, int LifeSpan); void SetClientLanguage(int ClientID, const char *pLanguage); + void InitChangelog(); + void ReloadChangelog(); private: int m_VoteLanguageTick[MAX_CLIENTS]; char m_VoteLanguage[MAX_CLIENTS][16]; int m_VoteBanClientID; static bool m_ClientMuted[MAX_CLIENTS][MAX_CLIENTS]; // m_ClientMuted[i][j]: i muted j + static array_on_stack m_aChangeLogEntries; + static array_on_stack m_aChangeLogPageIndices; class CBroadcastState {