diff --git a/amxmodx/amxmodx.cpp b/amxmodx/amxmodx.cpp index b3167c97..55d9c0d8 100755 --- a/amxmodx/amxmodx.cpp +++ b/amxmodx/amxmodx.cpp @@ -197,7 +197,7 @@ static cell AMX_NATIVE_CALL console_print(AMX *amx, cell *params) /* 2 param */ if (index < 1 || index > gpGlobals->maxClients) // Server console { - if (len > 254) + if (len > 254) // Server console truncates after byte 255. (254 + \n = 255) { len = 254; if ((message[len - 1] & 1 << 7)) @@ -216,18 +216,26 @@ static cell AMX_NATIVE_CALL console_print(AMX *amx, cell *params) /* 2 param */ if (pPlayer->ingame && !pPlayer->IsBot()) { - if (len > 126) // Client console truncates after byte 127. (126 + \n = 127) + if (len > 125) // Client console truncates after byte 127. (125 + \n\n = 127) { - len = 126; + len = 125; if ((message[len - 1] & 1 << 7)) { len -= UTIL_CheckValidChar(message + len - 1); // Don't truncate a multi-byte character } } - message[len++] = '\n'; // Client expects newline from the server + message[len++] = '\n'; + + const auto canUseFormatString = g_official_mod && !g_bmod_dod; // Temporary exclusion for DoD until officially supported + + if (canUseFormatString) + { + message[len++] = '\n'; // Double newline is required when pre-formatted string in TextMsg is passed as argument. + } + message[len] = 0; - UTIL_ClientPrint(pPlayer->pEdict, 2, message); + UTIL_ClientPrint(pPlayer->pEdict, HUD_PRINTCONSOLE, message); } } @@ -241,6 +249,8 @@ static cell AMX_NATIVE_CALL client_print(AMX *amx, cell *params) /* 3 param */ int len = 0; char *msg; + const auto canUseFormatString = g_official_mod && !g_bmod_dod; // Temporary exclusion for DoD until officially supported + if (params[1] == 0) // 0 = All players { for (int i = 1; i <= gpGlobals->maxClients; ++i) @@ -252,16 +262,38 @@ static cell AMX_NATIVE_CALL client_print(AMX *amx, cell *params) /* 3 param */ g_langMngr.SetDefLang(i); msg = format_amxstring(amx, params, 3, len); - // params[2]: print_notify = 1, print_console = 2, print_chat = 3, print_center = 4 - if (((params[2] == 1) || (params[2] == 2)) && (len > 126)) // Client console truncates after byte 127. (126 + \n = 127) + // Client console truncates after byte 127. + // If format string is used, limit includes double new lines (125 + \n\n), otherwise one new line (126 + \n). + const auto bytesLimit = canUseFormatString ? 125 : 126; + + if (g_bmod_cstrike && params[2] == HUD_PRINTCENTER) // Likely a temporary fix. { - len = 126; + for (int j = 0; j < len; ++j) + { + if (msg[j] == '\n') + { + msg[j] = '\r'; + } + } + } + else if (((params[2] == HUD_PRINTNOTIFY) || (params[2] == HUD_PRINTCONSOLE)) && (len > bytesLimit)) + { + len = bytesLimit; if ((msg[len - 1] & 1 << 7)) { len -= UTIL_CheckValidChar(msg + len - 1); // Don't truncate a multi-byte character } } - msg[len++] = '\n'; // Client expects newline from the server + msg[len++] = '\n'; + + if (canUseFormatString) + { + if (!g_bmod_cstrike || params[2] == HUD_PRINTNOTIFY || params[2] == HUD_PRINTCONSOLE) + { + msg[len++] = '\n'; // Double newline is required when pre-formatted string in TextMsg is passed as argument. + } + } + msg[len] = 0; UTIL_ClientPrint(pPlayer->pEdict, params[2], msg); @@ -286,16 +318,38 @@ static cell AMX_NATIVE_CALL client_print(AMX *amx, cell *params) /* 3 param */ msg = format_amxstring(amx, params, 3, len); - // params[2]: print_notify = 1, print_console = 2, print_chat = 3, print_center = 4 - if (((params[2] == 1) || (params[2] == 2)) && (len > 126)) // Client console truncates after byte 127. (126 + \n = 127) + // Client console truncates after byte 127. + // If format string is used, limit includes double new lines (125 + \n\n), otherwise one new line (126 + \n). + const auto bytesLimit = canUseFormatString ? 125 : 126; + + if (g_bmod_cstrike && params[2] == HUD_PRINTCENTER) // Likely a temporary fix. { - len = 126; + for (int j = 0; j < len; ++j) + { + if (msg[j] == '\n') + { + msg[j] = '\r'; + } + } + } + else if (((params[2] == HUD_PRINTNOTIFY) || (params[2] == HUD_PRINTCONSOLE)) && (len > bytesLimit)) // Client console truncates after byte 127. (125 + \n\n = 127) + { + len = bytesLimit; if ((msg[len - 1] & 1 << 7)) { len -= UTIL_CheckValidChar(msg + len - 1); // Don't truncate a multi-byte character } } - msg[len++] = '\n'; // Client expects newline from the server + msg[len++] = '\n'; + + if (canUseFormatString) + { + if (!g_bmod_cstrike || params[2] == HUD_PRINTNOTIFY || params[2] == HUD_PRINTCONSOLE) + { + msg[len++] = '\n'; // Double newline is required when pre-formatted string in TextMsg is passed as argument. + } + } + msg[len] = 0; UTIL_ClientPrint(pPlayer->pEdict, params[2], msg); @@ -344,16 +398,15 @@ static cell AMX_NATIVE_CALL client_print_color(AMX *amx, cell *params) /* 3 para *msg = 1; } - if (len > 190) // Server crashes after byte 190. (190 + \n = 191) + if (len > 187) // Max available bytes: 188 { - len = 190; + len = 187; if ((msg[len - 1] & 1 << 7)) { len -= UTIL_CheckValidChar(msg + len - 1); // Don't truncate a multi-byte character } } - - msg[len++] = '\n'; + msg[len] = 0; UTIL_ClientSayText(pPlayer->pEdict, sender ? sender : i, msg); @@ -382,16 +435,15 @@ static cell AMX_NATIVE_CALL client_print_color(AMX *amx, cell *params) /* 3 para *msg = 1; } - if (len > 190) // Server crashes after byte 190. (190 + \n = 191) + if (len > 187) // Max available bytes: 188 { - len = 190; + len = 187; if ((msg[len - 1] & 1 << 7)) { len -= UTIL_CheckValidChar(msg + len - 1); // Don't truncate a multi-byte character } } - msg[len++] = '\n'; msg[len] = 0; UTIL_ClientSayText(pPlayer->pEdict, sender ? sender : index, msg); diff --git a/amxmodx/amxmodx.h b/amxmodx/amxmodx.h index 7216793a..037662e9 100755 --- a/amxmodx/amxmodx.h +++ b/amxmodx/amxmodx.h @@ -188,6 +188,11 @@ extern WeaponsVault g_weaponsData[MAX_WEAPONS]; extern XVars g_xvars; extern bool g_bmod_cstrike; extern bool g_bmod_dod; +extern bool g_bmod_dmc; +extern bool g_bmod_ricochet; +extern bool g_bmod_valve; +extern bool g_bmod_gearbox; +extern bool g_official_mod; extern bool g_dontprecache; extern int g_srvindex; extern cvar_t* amxmodx_version; diff --git a/amxmodx/meta_api.cpp b/amxmodx/meta_api.cpp index 6a4e10ad..ca4334df 100755 --- a/amxmodx/meta_api.cpp +++ b/amxmodx/meta_api.cpp @@ -88,6 +88,11 @@ XVars g_xvars; bool g_bmod_tfc; bool g_bmod_cstrike; bool g_bmod_dod; +bool g_bmod_dmc; +bool g_bmod_ricochet; +bool g_bmod_valve; +bool g_bmod_gearbox; +bool g_official_mod; bool g_dontprecache; bool g_forcedmodules; bool g_forcedsounds; @@ -1800,6 +1805,7 @@ C_DLLEXPORT int GetEntityAPI2_Post(DLL_FUNCTIONS *pFunctionTable, int *interface } enginefuncs_t meta_engfuncs; + C_DLLEXPORT int GetEngineFunctions(enginefuncs_t *pengfuncsFromEngine, int *interfaceVersion) { memset(&meta_engfuncs, 0, sizeof(enginefuncs_t)); @@ -1809,11 +1815,17 @@ C_DLLEXPORT int GetEngineFunctions(enginefuncs_t *pengfuncsFromEngine, int *inte meta_engfuncs.pfnSetModel = C_SetModel; g_bmod_cstrike = true; } else { - g_bmod_cstrike = false; - g_bmod_dod = !stricmp(g_mod_name.chars(), "dod"); - g_bmod_tfc = !stricmp(g_mod_name.chars(), "tfc"); + g_bmod_cstrike = false; + g_bmod_dod = !stricmp(g_mod_name.chars(), "dod"); + g_bmod_dmc = !stricmp(g_mod_name.chars(), "dmc"); + g_bmod_tfc = !stricmp(g_mod_name.chars(), "tfc"); + g_bmod_ricochet = !stricmp(g_mod_name.chars(), "ricochet"); + g_bmod_valve = !stricmp(g_mod_name.chars(), "valve"); + g_bmod_gearbox = !stricmp(g_mod_name.chars(), "gearbox"); } + g_official_mod = g_bmod_cstrike || g_bmod_dod || g_bmod_dmc || g_bmod_ricochet || g_bmod_tfc || g_bmod_valve || g_bmod_gearbox; + meta_engfuncs.pfnCmd_Argc = C_Cmd_Argc; meta_engfuncs.pfnCmd_Argv = C_Cmd_Argv; meta_engfuncs.pfnCmd_Args = C_Cmd_Args; diff --git a/amxmodx/util.cpp b/amxmodx/util.cpp index b9b694af..25c55de1 100755 --- a/amxmodx/util.cpp +++ b/amxmodx/util.cpp @@ -260,42 +260,54 @@ void UTIL_DHudMessage(edict_t *pEntity, const hudtextparms_t &textparms, const c MESSAGE_END(); } -/* warning - buffer of msg must be longer than 187 chars! -(here in AMX it is always longer) */ +/** + * User message size limit: 192 bytes + * Actual available size: 188 bytes (with EOS) + */ void UTIL_ClientPrint(edict_t *pEntity, int msg_dest, char *msg) { if (!gmsgTextMsg) return; // :TODO: Maybe output a warning log? - char c = msg[187]; - msg[187] = 0; // truncate without checking with strlen() + const auto canUseFormatString = g_official_mod && !g_bmod_dod; // Temporary exclusion for DoD until officially supported + const auto index = canUseFormatString ? 187 : 190; + char c = msg[index]; + msg[index] = 0; // truncate without checking with strlen() if (pEntity) MESSAGE_BEGIN(MSG_ONE, gmsgTextMsg, NULL, pEntity); else MESSAGE_BEGIN(MSG_BROADCAST, gmsgTextMsg); - WRITE_BYTE(msg_dest); - WRITE_STRING("%s"); - WRITE_STRING(msg); - MESSAGE_END(); - msg[187] = c; + WRITE_BYTE(msg_dest); // 1 byte + if (canUseFormatString) + WRITE_STRING("%s"); // 3 bytes (2 + EOS) + WRITE_STRING(msg); // max 188 bytes (187 + EOS) + MESSAGE_END(); // max 192 bytes + msg[index] = c; } +/** + * User message size limit: 192 bytes + * Actual available size: 188 bytes (with EOS) + */ void UTIL_ClientSayText(edict_t *pEntity, int sender, char *msg) { if (!gmsgSayText) return; // :TODO: Maybe output a warning log? - char c = msg[187]; - msg[187] = 0; // truncate without checking with strlen() + const auto canUseFormatString = g_official_mod && !g_bmod_dod; // Temporary exclusion for DoD until officially supported + const auto index = canUseFormatString ? 187 : 190; + char c = msg[index]; + msg[index] = 0; // truncate without checking with strlen() MESSAGE_BEGIN(MSG_ONE, gmsgSayText, NULL, pEntity); - WRITE_BYTE(sender); - WRITE_STRING("%s"); - WRITE_STRING(msg); - MESSAGE_END(); - msg[187] = c; + WRITE_BYTE(sender); // 1 byte + if (canUseFormatString) + WRITE_STRING("%s"); // 3 bytes (2 + EOS) + WRITE_STRING(msg); // max 188 bytes (187 + EOS) + MESSAGE_END(); // max 192 bytes + msg[index] = c; } void UTIL_TeamInfo(edict_t *pEntity, int playerIndex, const char *pszTeamName)