diff --git a/configs/core.cfg b/configs/core.cfg index aac079af..c0d83e91 100644 --- a/configs/core.cfg +++ b/configs/core.cfg @@ -70,4 +70,13 @@ * to a previous menu. */ "MenuExitBackSound" "buttons/combine_button7.wav" + + /** + * Enables or disables whether SourceMod reads a client's cl_language cvar to set + * their language for server-side phrase translation. + * + * "on" - Translate using the client's language (default) + * "off" - Translate using default server's language + */ + "AllowClLanguageVar" "On" } diff --git a/core/ConVarManager.cpp b/core/ConVarManager.cpp index c4f0386d..1cd4d42e 100644 --- a/core/ConVarManager.cpp +++ b/core/ConVarManager.cpp @@ -37,6 +37,7 @@ #include "sm_srvcmds.h" #include "sm_stringutil.h" #include +#include "PlayerManager.h" ConVarManager g_ConVarManager; @@ -564,12 +565,18 @@ void ConVarManager::OnQueryCvarValueFinished(QueryCvarCookie_t cookie, edict_t * for (iter = m_ConVarQueries.begin(); iter != m_ConVarQueries.end(); iter++) { ConVarQuery &query = (*iter); - if (query.cookie == cookie) { pCallback = query.pCallback; value = query.value; + if (!pCallback) + { + g_Players.HandleLangQuery(engine->GetPlayerUserId(pPlayer), (result == eQueryCvarValueStatus_ValueIntact) ? cvarValue : "", cookie); + m_ConVarQueries.erase(iter); + return; + } + break; } } diff --git a/core/PlayerManager.cpp b/core/PlayerManager.cpp index 88f708c9..4621c1c6 100644 --- a/core/PlayerManager.cpp +++ b/core/PlayerManager.cpp @@ -41,7 +41,10 @@ #include #include #include "TimerSys.h" +#include "Translator.h" +#include "ConVarManager.h" #include "Logger.h" +#include "HalfLife2.h" PlayerManager g_Players; bool g_OnMapStarted = false; @@ -190,6 +193,17 @@ ConfigResult PlayerManager::OnSourceModConfigChanged(const char *key, m_PassInfoVar.assign(value); } return ConfigResult_Accept; + } else if (strcmp(key, "AllowClLanguageVar") == 0) { + if (strcasecmp(value, "on") == 0) + { + m_QueryLang = true; + } else if (strcasecmp(value, "off") == 0) { + m_QueryLang = false; + } else { + UTIL_Format(error, maxlength, "Invalid value: must be \"on\" or \"off\""); + return ConfigResult_Reject; + } + return ConfigResult_Accept; } return ConfigResult_Ignore; } @@ -486,6 +500,18 @@ void PlayerManager::OnClientPutInServer(edict_t *pEntity, const char *playername pPlayer->m_Info = playerinfo->GetPlayerInfo(pEntity); } + /* Query the client's language */ + if (m_QueryLang) + { + if (!pPlayer->IsFakeClient() && !g_IsOriginalEngine) + { + pPlayer->m_LangCookie = g_ConVarManager.QueryClientConVar(pPlayer->GetEdict(), "cl_language", NULL, 0); + } else { + /* Skip the query if this is a bot or if we cant query cvars*/ + pPlayer->m_LangId = g_Translator.GetServerLanguage(); + } + } + #if defined CLIENT_DEBUG g_Logger.LogMessage("[CL_DEBUG] OnClientPutInServer() (m_Info %p)", pPlayer->m_Info); #endif @@ -820,6 +846,27 @@ void PlayerManager::RecheckAnyAdmins() } } +void PlayerManager::HandleLangQuery(int userid, const char *value, QueryCvarCookie_t cookie) +{ + int id = GetClientOfUserId(userid); + if (id == 0) + { + return; + } + + CPlayer *pl = GetPlayerByIndex(id); + + unsigned int langid; + if (pl->m_LangCookie == cookie) + { + if (value[0] != '\0' && g_Translator.GetLanguageByName(value, &langid)) + { + pl->m_LangId = langid; + } else { + pl->m_LangId = g_Translator.GetServerLanguage(); + } + } +} /******************* *** PLAYER CODE *** @@ -836,6 +883,8 @@ CPlayer::CPlayer() m_Info = NULL; m_bAdminCheckSignalled = false; m_LastPassword.clear(); + m_LangId = LANGUAGE_ENGLISH; + m_LangCookie = 0; } void CPlayer::Initialize(const char *name, const char *ip, edict_t *pEntity) @@ -845,6 +894,8 @@ void CPlayer::Initialize(const char *name, const char *ip, edict_t *pEntity) m_Ip.assign(ip); m_pEdict = pEntity; m_iIndex = engine->IndexOfEdict(pEntity); + m_LangId = g_Translator.GetServerLanguage(); + m_LangCookie = 0; char ip2[24], *ptr; strncopy(ip2, ip, sizeof(ip2)); @@ -1081,6 +1132,11 @@ void CPlayer::DoBasicAdminChecks() } } +unsigned int CPlayer::GetLanguageId() +{ + return m_LangId; +} + int CPlayer::GetUserId() { if (m_UserId == -1) diff --git a/core/PlayerManager.h b/core/PlayerManager.h index 727773e8..bc45ccfc 100644 --- a/core/PlayerManager.h +++ b/core/PlayerManager.h @@ -62,6 +62,7 @@ public: AdminId GetAdminId(); void Kick(const char *str); IPlayerInfo *GetPlayerInfo(); + unsigned int GetLanguageId(); int GetUserId(); public: void NotifyPostAdminChecks(); @@ -90,6 +91,8 @@ private: String m_LastPassword; bool m_bAdminCheckSignalled; int m_iIndex; + unsigned int m_LangId; + QueryCvarCookie_t m_LangCookie; int m_UserId; }; @@ -127,6 +130,7 @@ public: //IPlayerManager int GetMaxClients(); int GetNumPlayers(); int GetClientOfUserId(int userid); + void HandleLangQuery(int userid, const char *value, QueryCvarCookie_t cookie); public: inline int MaxClients() { @@ -160,6 +164,7 @@ private: bool m_FirstPass; unsigned int *m_AuthQueue; String m_PassInfoVar; + bool m_QueryLang; }; extern PlayerManager g_Players; diff --git a/core/Translator.cpp b/core/Translator.cpp index 9e559995..9e6d0095 100644 --- a/core/Translator.cpp +++ b/core/Translator.cpp @@ -38,6 +38,7 @@ #include "LibrarySys.h" #include "sm_stringutil.h" #include "sourcemod.h" +#include "PlayerManager.h" Translator g_Translator; CPhraseFile *g_pCorePhrases = NULL; @@ -736,6 +737,32 @@ bool Translator::GetLanguageByCode(const char *code, unsigned int *index) return true; } +bool Translator::GetLanguageByName(const char *name, unsigned int *index) +{ + CVector::iterator iter; + unsigned int id = 0; + + for (iter=m_Languages.begin(); iter!=m_Languages.end(); iter++, id++) + { + if (strcasecmp(m_pStringTab->GetString((*iter)->m_FullName), name) == 0) + { + break; + } + } + + if (iter == m_Languages.end()) + { + return false; + } + + if (index) + { + *index = id; + } + + return true; +} + unsigned int Translator::GetLanguageCount() { return (unsigned int)m_Languages.size(); @@ -948,7 +975,8 @@ unsigned int Translator::GetServerLanguage() unsigned int Translator::GetClientLanguage(int client) { - return GetServerLanguage(); + CPlayer *pPlayer = g_Players.GetPlayerByIndex(client); + return pPlayer->GetLanguageId(); } bool Translator::GetLanguageInfo(unsigned int number, const char **code, const char **name) diff --git a/core/Translator.h b/core/Translator.h index 959fd6d0..f04ba473 100644 --- a/core/Translator.h +++ b/core/Translator.h @@ -139,6 +139,7 @@ public: unsigned int GetLanguageCount(); bool GetLanguageInfo(unsigned int number, const char **code, const char **name); bool GetLanguageByCode(const char *code, unsigned int *index); + bool GetLanguageByName(const char *name, unsigned int *index); size_t Translate(char *buffer, size_t maxlength, void **params, const Translation *pTrans); CPhraseFile *GetFileByIndex(unsigned int index); TransError CoreTrans(int client, diff --git a/core/sm_stringutil.cpp b/core/sm_stringutil.cpp index 63599a16..03d3bd55 100644 --- a/core/sm_stringutil.cpp +++ b/core/sm_stringutil.cpp @@ -55,10 +55,14 @@ size_t CorePlayerTranslate(int client, char *buffer, size_t maxlength, const cha Translation pTrans; TransError err; - err = g_pCorePhrases->GetTranslation(phrase, g_Translator.GetServerLanguage(), &pTrans); - if (err != Trans_Okay && g_Translator.GetServerLanguage() != CORELANG_ENGLISH) + err = g_pCorePhrases->GetTranslation(phrase, g_Translator.GetClientLanguage(client), &pTrans); + if (err != Trans_Okay) { - err = g_pCorePhrases->GetTranslation(phrase, CORELANG_ENGLISH, &pTrans); + err = g_pCorePhrases->GetTranslation(phrase, g_Translator.GetServerLanguage(), &pTrans); + if (err != Trans_Okay && g_Translator.GetServerLanguage() != CORELANG_ENGLISH) + { + err = g_pCorePhrases->GetTranslation(phrase, CORELANG_ENGLISH, &pTrans); + } } if (err != Trans_Okay) @@ -123,7 +127,7 @@ try_serverlang: } max_params = pTrans.fmt_count; - + if (max_params) { /* Check if we're going to over the limit */ diff --git a/public/IPlayerHelpers.h b/public/IPlayerHelpers.h index 7490d865..4d861653 100644 --- a/public/IPlayerHelpers.h +++ b/public/IPlayerHelpers.h @@ -123,6 +123,13 @@ namespace SourceMod */ virtual void SetAdminId(AdminId id, bool temp) =0; + /** + * @brief Returns the client's language id. + * + * @return Language id. + */ + virtual unsigned int GetLanguageId() =0; + /** * @brief Returns the client's userid. *