diff options
| author | navewindre <nw@moneybot.cc> | 2023-12-04 18:06:10 +0100 |
|---|---|---|
| committer | navewindre <nw@moneybot.cc> | 2023-12-04 18:06:10 +0100 |
| commit | aef0d1c1268ab7d4bc18996c9c6b4da16a40aadc (patch) | |
| tree | 43e766b51704f4ab8b383583bdc1871eeeb9c698 /sourcemod/scripting/gokz-quiet/hideplayers.sp | |
| parent | 38f1140c11724da05a23a10385061200b907cf6e (diff) | |
bbbbbbbbwaaaaaaaaaaa
Diffstat (limited to 'sourcemod/scripting/gokz-quiet/hideplayers.sp')
| -rw-r--r-- | sourcemod/scripting/gokz-quiet/hideplayers.sp | 309 |
1 files changed, 309 insertions, 0 deletions
diff --git a/sourcemod/scripting/gokz-quiet/hideplayers.sp b/sourcemod/scripting/gokz-quiet/hideplayers.sp new file mode 100644 index 0000000..65736f0 --- /dev/null +++ b/sourcemod/scripting/gokz-quiet/hideplayers.sp @@ -0,0 +1,309 @@ +/* + Hide sounds and effects from other players. +*/ + +void OnPluginStart_HidePlayers() +{ + AddNormalSoundHook(Hook_NormalSound); + AddTempEntHook("Shotgun Shot", Hook_ShotgunShot); + AddTempEntHook("EffectDispatch", Hook_EffectDispatch); + HookUserMessage(GetUserMessageId("WeaponSound"), Hook_WeaponSound, true); + + // Lateload support + for (int client = 1; client <= MaxClients; client++) + { + if (IsValidClient(client)) + { + OnJoinTeam_HidePlayers(client, GetClientTeam(client)); + } + } +} + +void OnJoinTeam_HidePlayers(int client, int team) +{ + // Make sure client is only ever hooked once + SDKUnhook(client, SDKHook_SetTransmit, OnSetTransmitClient); + + if (team == CS_TEAM_T || team == CS_TEAM_CT) + { + SDKHook(client, SDKHook_SetTransmit, OnSetTransmitClient); + } +} + +Action CommandToggleShowPlayers(int client, int args) +{ + if (GOKZ_GetOption(client, gC_QTOptionNames[QTOption_ShowPlayers]) == ShowPlayers_Disabled) + { + GOKZ_SetOption(client, gC_QTOptionNames[QTOption_ShowPlayers], ShowPlayers_Enabled); + } + else + { + GOKZ_SetOption(client, gC_QTOptionNames[QTOption_ShowPlayers], ShowPlayers_Disabled); + } + return Plugin_Handled; +} + +// =====[ PRIVATE ]===== + +// Hide most of the other players' actions. This function is expensive. +static Action OnSetTransmitClient(int entity, int client) +{ + if (GOKZ_GetOption(client, gC_QTOptionNames[QTOption_ShowPlayers]) == ShowPlayers_Disabled + && entity != client + && entity != GetObserverTarget(client)) + { + return Plugin_Handled; + } + return Plugin_Continue; +} + +// Hide reload sounds. Required if other players were visible at one point during the gameplay. +static Action Hook_WeaponSound(UserMsg msg_id, Protobuf msg, const int[] players, int playersNum, bool reliable, bool init) +{ + int newClients[MAXPLAYERS], newTotal = 0; + int entidx = msg.ReadInt("entidx"); + for (int i = 0; i < playersNum; i++) + { + int client = players[i]; + if (GOKZ_GetOption(client, gC_QTOptionNames[QTOption_ShowPlayers]) == ShowPlayers_Enabled + || entidx == client + || entidx == GetObserverTarget(client)) + { + newClients[newTotal] = client; + newTotal++; + } + } + + // Nothing's changed, let the engine handle it. + if (newTotal == playersNum) + { + return Plugin_Continue; + } + // No one to send to so it doesn't matter if we block or not. We block just to end the function early. + if (newTotal == 0) + { + return Plugin_Handled; + } + // Only way to modify the recipient list is to RequestFrame and create our own user message. + char path[PLATFORM_MAX_PATH]; + msg.ReadString("sound", path, sizeof(path)); + int flags = USERMSG_BLOCKHOOKS; + if (reliable) + { + flags |= USERMSG_RELIABLE; + } + if (init) + { + flags |= USERMSG_INITMSG; + } + + DataPack dp = new DataPack(); + dp.WriteCell(msg_id); + dp.WriteCell(newTotal); + dp.WriteCellArray(newClients, newTotal); + dp.WriteCell(flags); + dp.WriteCell(entidx); + dp.WriteFloat(msg.ReadFloat("origin_x")); + dp.WriteFloat(msg.ReadFloat("origin_y")); + dp.WriteFloat(msg.ReadFloat("origin_z")); + dp.WriteString(path); + dp.WriteFloat(msg.ReadFloat("timestamp")); + + RequestFrame(RequestFrame_WeaponSound, dp); + return Plugin_Handled; +} + +static void RequestFrame_WeaponSound(DataPack dp) +{ + dp.Reset(); + + UserMsg msg_id = dp.ReadCell(); + int newTotal = dp.ReadCell(); + int newClients[MAXPLAYERS]; + dp.ReadCellArray(newClients, newTotal); + int flags = dp.ReadCell(); + + Protobuf newMsg = view_as<Protobuf>(StartMessageEx(msg_id, newClients, newTotal, flags)); + + newMsg.SetInt("entidx", dp.ReadCell()); + newMsg.SetFloat("origin_x", dp.ReadFloat()); + newMsg.SetFloat("origin_y", dp.ReadFloat()); + newMsg.SetFloat("origin_z", dp.ReadFloat()); + char path[PLATFORM_MAX_PATH]; + dp.ReadString(path, sizeof(path)); + newMsg.SetString("sound", path); + newMsg.SetFloat("timestamp", dp.ReadFloat()); + + EndMessage(); + + delete dp; +} + +// Hide various sounds that don't get blocked by SetTransmit hook. +static Action Hook_NormalSound(int clients[MAXPLAYERS], int& numClients, char sample[PLATFORM_MAX_PATH], int& entity, int& channel, float& volume, int& level, int& pitch, int& flags, char soundEntry[PLATFORM_MAX_PATH], int& seed) +{ + if (StrContains(sample, "Player.EquipArmor") != -1 || StrContains(sample, "BaseCombatCharacter.AmmoPickup") != -1) + { + // When the sound is emitted, the owner of these entities are not set yet. + // Hence we cannot do the entity parent stuff below. + // In that case, we just straight up block armor and ammo pickup sounds. + return Plugin_Stop; + } + int ent = entity; + while (ent > MAXPLAYERS) + { + // Block some gun and knife sounds by trying to find its parent entity. + ent = GetEntPropEnt(ent, Prop_Send, "moveparent"); + if (ent < MAXPLAYERS) + { + break; + } + else if (ent == -1) + { + return Plugin_Continue; + } + } + int numNewClients = 0; + for (int i = 0; i < numClients; i++) + { + int client = clients[i]; + if (GOKZ_GetOption(client, gC_QTOptionNames[QTOption_ShowPlayers]) == ShowPlayers_Enabled + || ent == client + || ent == GetObserverTarget(client)) + { + clients[numNewClients] = client; + numNewClients++; + } + } + + if (numNewClients != numClients) + { + numClients = numNewClients; + return Plugin_Changed; + } + + return Plugin_Continue; +} + +// Hide firing sounds. +static Action Hook_ShotgunShot(const char[] te_name, const int[] players, int numClients, float delay) +{ + int newClients[MAXPLAYERS], newTotal = 0; + for (int i = 0; i < numClients; i++) + { + int client = players[i]; + if (GOKZ_GetOption(client, gC_QTOptionNames[QTOption_ShowPlayers]) == ShowPlayers_Enabled + || TE_ReadNum("m_iPlayer") + 1 == GetObserverTarget(client)) + { + newClients[newTotal] = client; + newTotal++; + } + } + + // Noone wants the sound + if (newTotal == 0) + { + return Plugin_Stop; + } + + // Nothing's changed, let the engine handle it. + if (newTotal == numClients) + { + return Plugin_Continue; + } + + float origin[3]; + TE_ReadVector("m_vecOrigin", origin); + + float angles[2]; + angles[0] = TE_ReadFloat("m_vecAngles[0]"); + angles[1] = TE_ReadFloat("m_vecAngles[1]"); + + int weapon = TE_ReadNum("m_weapon"); + int mode = TE_ReadNum("m_iMode"); + int seed = TE_ReadNum("m_iSeed"); + int player = TE_ReadNum("m_iPlayer"); + float inaccuracy = TE_ReadFloat("m_fInaccuracy"); + float recoilIndex = TE_ReadFloat("m_flRecoilIndex"); + float spread = TE_ReadFloat("m_fSpread"); + int itemIdx = TE_ReadNum("m_nItemDefIndex"); + int soundType = TE_ReadNum("m_iSoundType"); + + TE_Start("Shotgun Shot"); + TE_WriteVector("m_vecOrigin", origin); + TE_WriteFloat("m_vecAngles[0]", angles[0]); + TE_WriteFloat("m_vecAngles[1]", angles[1]); + TE_WriteNum("m_weapon", weapon); + TE_WriteNum("m_iMode", mode); + TE_WriteNum("m_iSeed", seed); + TE_WriteNum("m_iPlayer", player); + TE_WriteFloat("m_fInaccuracy", inaccuracy); + TE_WriteFloat("m_flRecoilIndex", recoilIndex); + TE_WriteFloat("m_fSpread", spread); + TE_WriteNum("m_nItemDefIndex", itemIdx); + TE_WriteNum("m_iSoundType", soundType); + + // Send the TE and stop the engine from processing its own. + TE_Send(newClients, newTotal, delay); + return Plugin_Stop; +} + +// Hide knife and blood effect caused by other players. +static Action Hook_EffectDispatch(const char[] te_name, const int[] players, int numClients, float delay) +{ + // Block bullet impact effects. + int effIndex = TE_ReadNum("m_iEffectName"); + if (effIndex != EFFECT_IMPACT && effIndex != EFFECT_KNIFESLASH) + { + return Plugin_Continue; + } + int newClients[MAXPLAYERS], newTotal = 0; + for (int i = 0; i < numClients; i++) + { + int client = players[i]; + if (GOKZ_GetOption(client, gC_QTOptionNames[QTOption_ShowPlayers]) == ShowPlayers_Enabled) + { + newClients[newTotal] = client; + newTotal++; + } + } + // Noone wants the sound + if (newTotal == 0) + { + return Plugin_Stop; + } + + // Nothing's changed, let the engine handle it. + if (newTotal == numClients) + { + return Plugin_Continue; + } + float origin[3], start[3]; + origin[0] = TE_ReadFloat("m_vOrigin.x"); + origin[1] = TE_ReadFloat("m_vOrigin.y"); + origin[2] = TE_ReadFloat("m_vOrigin.z"); + start[0] = TE_ReadFloat("m_vStart.x"); + start[1] = TE_ReadFloat("m_vStart.y"); + start[2] = TE_ReadFloat("m_vStart.z"); + int flags = TE_ReadNum("m_fFlags"); + float scale = TE_ReadFloat("m_flScale"); + int surfaceProp = TE_ReadNum("m_nSurfaceProp"); + int damageType = TE_ReadNum("m_nDamageType"); + int entindex = TE_ReadNum("entindex"); + int positionsAreRelativeToEntity = TE_ReadNum("m_bPositionsAreRelativeToEntity"); + + TE_Start("EffectDispatch"); + TE_WriteNum("m_iEffectName", effIndex); + TE_WriteFloatArray("m_vOrigin.x", origin, 3); + TE_WriteFloatArray("m_vStart.x", start, 3); + TE_WriteFloat("m_flScale", scale); + TE_WriteNum("m_nSurfaceProp", surfaceProp); + TE_WriteNum("m_nDamageType", damageType); + TE_WriteNum("entindex", entindex); + TE_WriteNum("m_bPositionsAreRelativeToEntity", positionsAreRelativeToEntity); + TE_WriteNum("m_fFlags", flags); + + // Send the TE and stop the engine from processing its own. + TE_Send(newClients, newTotal, delay); + return Plugin_Stop; +} |
