Split emoticon sending into nearby and global players

This commit is contained in:
Jupeyy 2023-06-11 13:24:02 +02:00
parent 6a53d72b35
commit 845ba50842
7 changed files with 101 additions and 64 deletions

View file

@ -222,7 +222,8 @@ MACRO_CONFIG_INT(SvInviteFrequency, sv_invite_frequency, 1, 0, 9999, CFGFLAG_SER
MACRO_CONFIG_INT(SvTeleOthersAuthLevel, sv_tele_others_auth_level, 1, 1, 3, CFGFLAG_SERVER, "The auth level you need to tele others")
MACRO_CONFIG_INT(SvEmotionalTees, sv_emotional_tees, 1, -1, 1, CFGFLAG_SERVER, "Whether eye change of tees is enabled with emoticons = 1, not = 0, -1 not at all")
MACRO_CONFIG_INT(SvEmoticonDelay, sv_emoticon_delay, 3, 0, 9999, CFGFLAG_SERVER, "The time in seconds between over-head emoticons")
MACRO_CONFIG_INT(SvEmoticonMsDelay, sv_emoticon_ms_delay, 3000, 20, 999999999, CFGFLAG_SERVER, "The time in ms a player has to wait before allowing the next over-head emoticons")
MACRO_CONFIG_INT(SvGlobalEmoticonMsDelay, sv_global_emoticon_ms_delay, 3000, 20, 999999999, CFGFLAG_SERVER, "The time in ms a player has to wait before allowing the next over-head emoticons that is send to all clients (this config must be higher or equal to sv_emoticon_ms_delay to have an effect)")
MACRO_CONFIG_INT(SvEyeEmoteChangeDelay, sv_eye_emote_change_delay, 1, 0, 9999, CFGFLAG_SERVER, "The time in seconds between eye emoticons change")
MACRO_CONFIG_INT(SvChatDelay, sv_chat_delay, 1, 0, 9999, CFGFLAG_SERVER, "The time in seconds between chat messages")

View file

@ -1119,6 +1119,35 @@ bool CCharacter::CanSnapCharacter(int SnappingClient)
return true;
}
bool CCharacter::IsSnappingCharacterInView(int SnappingClientID)
{
int ID = m_pPlayer->GetCID();
// A player may not be clipped away if his hook or a hook attached to him is in the field of view
bool PlayerAndHookNotInView = NetworkClippedLine(SnappingClientID, m_Pos, m_Core.m_HookPos);
bool AttachedHookInView = false;
if(PlayerAndHookNotInView)
{
for(const auto &AttachedPlayerID : m_Core.m_AttachedPlayers)
{
CCharacter *pOtherPlayer = GameServer()->GetPlayerChar(AttachedPlayerID);
if(pOtherPlayer && pOtherPlayer->m_Core.m_HookedPlayer == ID)
{
if(!NetworkClippedLine(SnappingClientID, m_Pos, pOtherPlayer->m_Pos))
{
AttachedHookInView = true;
break;
}
}
}
}
if(PlayerAndHookNotInView && !AttachedHookInView)
{
return false;
}
return true;
}
void CCharacter::Snap(int SnappingClient)
{
int ID = m_pPlayer->GetCID();
@ -1131,28 +1160,8 @@ void CCharacter::Snap(int SnappingClient)
return;
}
// A player may not be clipped away if his hook or a hook attached to him is in the field of view
bool PlayerAndHookNotInView = NetworkClippedLine(SnappingClient, m_Pos, m_Core.m_HookPos);
bool AttachedHookInView = false;
if(PlayerAndHookNotInView)
{
for(const auto &AttachedPlayerID : m_Core.m_AttachedPlayers)
{
CCharacter *pOtherPlayer = GameServer()->GetPlayerChar(AttachedPlayerID);
if(pOtherPlayer && pOtherPlayer->m_Core.m_HookedPlayer == ID)
{
if(!NetworkClippedLine(SnappingClient, m_Pos, pOtherPlayer->m_Pos))
{
AttachedHookInView = true;
break;
}
}
}
}
if(PlayerAndHookNotInView && !AttachedHookInView)
{
if(!IsSnappingCharacterInView(SnappingClient))
return;
}
SnapCharacter(SnappingClient, ID);

View file

@ -41,6 +41,7 @@ public:
void SwapClients(int Client1, int Client2) override;
bool CanSnapCharacter(int SnappingClient);
bool IsSnappingCharacterInView(int SnappingClientID);
bool IsGrounded();

View file

@ -613,12 +613,12 @@ void CGameContext::SendStartWarning(int ClientID, const char *pMessage)
}
}
void CGameContext::SendEmoticon(int ClientID, int Emoticon)
void CGameContext::SendEmoticon(int ClientID, int Emoticon, int TargetClientID)
{
CNetMsg_Sv_Emoticon Msg;
Msg.m_ClientID = ClientID;
Msg.m_Emoticon = Emoticon;
Server()->SendPackMsg(&Msg, MSGFLAG_VITAL, -1);
Server()->SendPackMsg(&Msg, MSGFLAG_VITAL, TargetClientID);
}
void CGameContext::SendWeaponPickup(int ClientID, int Weapon)
@ -2526,50 +2526,75 @@ void CGameContext::OnMessage(int MsgID, CUnpacker *pUnpacker, int ClientID)
{
CNetMsg_Cl_Emoticon *pMsg = (CNetMsg_Cl_Emoticon *)pRawMsg;
if(g_Config.m_SvSpamprotection && pPlayer->m_LastEmote &&
pPlayer->m_LastEmote + maximum(Server()->TickSpeed() * g_Config.m_SvEmoticonDelay, g_Config.m_SvHighBandwidth ? 1 : 2) > Server()->Tick())
auto &&CheckPreventEmote = [&](int64_t LastEmote, int64_t DelayInMs) {
return (LastEmote * (int64_t)1000) + (int64_t)Server()->TickSpeed() * DelayInMs > ((int64_t)Server()->Tick() * (int64_t)1000);
};
if(g_Config.m_SvSpamprotection && CheckPreventEmote((int64_t)pPlayer->m_LastEmote, (int64_t)g_Config.m_SvEmoticonMsDelay))
return;
pPlayer->m_LastEmote = Server()->Tick();
pPlayer->UpdatePlaytime();
SendEmoticon(ClientID, pMsg->m_Emoticon);
CCharacter *pChr = pPlayer->GetCharacter();
if(pChr && g_Config.m_SvEmotionalTees && pPlayer->m_EyeEmoteEnabled)
// player needs a character to send emotes
if(pChr != nullptr)
{
int EmoteType = EMOTE_NORMAL;
switch(pMsg->m_Emoticon)
pPlayer->m_LastEmote = Server()->Tick();
pPlayer->UpdatePlaytime();
// check if the global emoticon is prevented and emotes are only send to nearby players
if(g_Config.m_SvSpamprotection && CheckPreventEmote((int64_t)pPlayer->m_LastEmoteGlobal, (int64_t)g_Config.m_SvGlobalEmoticonMsDelay))
{
case EMOTICON_EXCLAMATION:
case EMOTICON_GHOST:
case EMOTICON_QUESTION:
case EMOTICON_WTF:
EmoteType = EMOTE_SURPRISE;
break;
case EMOTICON_DOTDOT:
case EMOTICON_DROP:
case EMOTICON_ZZZ:
EmoteType = EMOTE_BLINK;
break;
case EMOTICON_EYES:
case EMOTICON_HEARTS:
case EMOTICON_MUSIC:
EmoteType = EMOTE_HAPPY;
break;
case EMOTICON_OOP:
case EMOTICON_SORRY:
case EMOTICON_SUSHI:
EmoteType = EMOTE_PAIN;
break;
case EMOTICON_DEVILTEE:
case EMOTICON_SPLATTEE:
case EMOTICON_ZOMG:
EmoteType = EMOTE_ANGRY;
break;
default:
break;
for(int i = 0; i < MAX_CLIENTS; ++i)
{
if(Server()->Translate(ClientID, i) &&
m_apPlayers[i] && pChr->CanSnapCharacter(i) && pChr->IsSnappingCharacterInView(i))
{
SendEmoticon(ClientID, pMsg->m_Emoticon, i);
}
}
}
else
{
// else send emoticons to all players
pPlayer->m_LastEmoteGlobal = Server()->Tick();
SendEmoticon(ClientID, pMsg->m_Emoticon, -1);
}
if(g_Config.m_SvEmotionalTees && pPlayer->m_EyeEmoteEnabled)
{
int EmoteType = EMOTE_NORMAL;
switch(pMsg->m_Emoticon)
{
case EMOTICON_EXCLAMATION:
case EMOTICON_GHOST:
case EMOTICON_QUESTION:
case EMOTICON_WTF:
EmoteType = EMOTE_SURPRISE;
break;
case EMOTICON_DOTDOT:
case EMOTICON_DROP:
case EMOTICON_ZZZ:
EmoteType = EMOTE_BLINK;
break;
case EMOTICON_EYES:
case EMOTICON_HEARTS:
case EMOTICON_MUSIC:
EmoteType = EMOTE_HAPPY;
break;
case EMOTICON_OOP:
case EMOTICON_SORRY:
case EMOTICON_SUSHI:
EmoteType = EMOTE_PAIN;
break;
case EMOTICON_DEVILTEE:
case EMOTICON_SPLATTEE:
case EMOTICON_ZOMG:
EmoteType = EMOTE_ANGRY;
break;
default:
break;
}
pChr->SetEmote(EmoteType, Server()->Tick() + 2 * Server()->TickSpeed());
}
pChr->SetEmote(EmoteType, Server()->Tick() + 2 * Server()->TickSpeed());
}
}
else if(MsgID == NETMSGTYPE_CL_KILL && !m_World.m_Paused)

View file

@ -250,7 +250,7 @@ public:
void SendChatTeam(int Team, const char *pText);
void SendChat(int ClientID, int Team, const char *pText, int SpamProtectionClientID = -1, int Flags = CHAT_SIX | CHAT_SIXUP);
void SendStartWarning(int ClientID, const char *pMessage);
void SendEmoticon(int ClientID, int Emoticon);
void SendEmoticon(int ClientID, int Emoticon, int TargetClientID);
void SendWeaponPickup(int ClientID, int Weapon);
void SendMotd(int ClientID);
void SendSettings(int ClientID);

View file

@ -278,7 +278,7 @@ void CPlayer::Tick()
{
if(1200 - ((Server()->Tick() - m_pCharacter->GetLastAction()) % (1200)) < 5)
{
GameServer()->SendEmoticon(GetCID(), EMOTICON_GHOST);
GameServer()->SendEmoticon(GetCID(), EMOTICON_GHOST, -1);
}
}
}

View file

@ -93,6 +93,7 @@ public:
int m_LastSetSpectatorMode;
int m_LastChangeInfo;
int m_LastEmote;
int m_LastEmoteGlobal;
int m_LastKill;
int m_aLastCommands[4];
int m_LastCommandPos;