diff --git a/CELT_VOICE/scripting/nosteam_celt_audio_no_zr.sp b/CELT_VOICE/scripting/nosteam_celt_audio_no_zr.sp new file mode 100644 index 0000000..a3d837f --- /dev/null +++ b/CELT_VOICE/scripting/nosteam_celt_audio_no_zr.sp @@ -0,0 +1,333 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#pragma semicolon 1 +#pragma newdecls required + +Handle g_hCheckMutes = null; +Handle g_hCookieTorchMuted = null; + +bool g_bWebclient[MAXPLAYERS + 1]; +bool g_bReRunWebClientName; + +char g_sLastWebclientIp[64]; + +public Plugin myinfo = +{ + name = "NoSteam CELT Voice override", + author = "jenz", + version = "1.5" +}; + +public void OnPluginStart() +{ + Format(g_sLastWebclientIp, sizeof(g_sLastWebclientIp), ""); + g_hCheckMutes = CreateTimer(2.0, check_mutes, _, TIMER_REPEAT); + g_hCookieTorchMuted = RegClientCookie("torch_muted", "is torch muted", CookieAccess_Protected); +} + +public void OnPluginEnd() +{ + if (g_hCheckMutes != null) + { + delete g_hCheckMutes; + } +} + +public void set_nosteam_listen_override(int client) +{ + for (int j = 1; j <= MaxClients; j++) + { + if (!IsValidClient(j) || client == j || IsFakeClient(j)) + continue; + if (PM_IsPlayerSteam(j)) + { + //the nosteam client is not allowed to hear the steam client because broadcastvoicedata would ear rape them. + //LogMessage("%N has muted %N", client, j); + SetListenOverride(client, j, Listen_No); + } + } +} + +public Action check_mutes(Handle timer, any data) +{ + for (int i = 1; i <= MaxClients; i++) + { + if (!IsValidClient(i) || IsFakeClient(i)) + { + continue; + } + if (!PM_IsPlayerSteam(i)) + { + set_nosteam_listen_override(i); + } + for (int j = 1; j <= MaxClients; j++) + { + if (!IsValidClient(j) || i == j || IsFakeClient(j)) + { + continue; + } + bool isMuted = BaseComm_IsClientMuted(j); + if (!isMuted) + { + isMuted = SelfMute_IsIgnoring(i, j); + } + //PrintToChatAll("i: %N. j: %N. isMuted: %i", i, j, isMuted); + ClientMutedOtherClient(i, j, isMuted); + } + if (g_bReRunWebClientName && g_bWebclient[i]) + { + char dummy[64]; + OnClientAuthorized(i, dummy); + g_bReRunWebClientName = false; + } + } + + + //sourceTV special case, index 0. + for (int j = 1; j <= MaxClients; j++) + { + if (!IsValidClient(j) || IsFakeClient(j)) + { + continue; + } + //yeah its monkey work but server can probably handle it fine. + char sBuffer[2]; + GetClientCookie(j, g_hCookieTorchMuted, sBuffer, sizeof(sBuffer)); + //PrintToChatAll("sBuffer: %s. j: %N", sBuffer, j); + if(sBuffer[0] != '\0') + { + ClientMutedOtherClient(j, 0, true); + } + else + { + ClientMutedOtherClient(j, 0, false); + } + } + + //check if webclient has new IP every 2 seconds through endpoint. + PollWebclientCurrentIp(); + return Plugin_Continue; +} + +//AI slop +public void SendWebclientNameToSignaling(const char[] webclientName) +{ + char url[256]; + // Adjust port/path to match your signaling servers actual endpoint + FormatEx(url, sizeof(url), "http://127.0.0.1:3000/webclient-name"); + + Handle hRequest = SteamWorks_CreateHTTPRequest(k_EHTTPMethodPOST, url); + if (hRequest == null) + { + return; + } + + // Send the name as a POST body parameter + SteamWorks_SetHTTPRequestGetOrPostParameter(hRequest, "name", webclientName); + + if (!SteamWorks_SetHTTPCallbacks(hRequest, OnWebclientNamePosted) || + !SteamWorks_SendHTTPRequest(hRequest)) + { + delete hRequest; + } +} + +public int OnWebclientNamePosted(Handle hRequest, bool bFailure, bool bRequestSuccessful, + EHTTPStatusCode eStatusCode, any data) +{ + // Fire-and-forget: we dont care about the response, just clean up. + delete hRequest; + return 0; +} + +public void OnMapStart() +{ + g_bReRunWebClientName = true; +} + +public void OnClientDisconnect(int client) +{ + g_bWebclient[client] = false; +} + +public void OnClientPostAdminCheck(int client) +{ + g_bWebclient[client] = false; + if (IsFakeClient(client)) + { + return; + } + + char sIP[32]; + GetClientIP(client, sIP, sizeof(sIP)); + + char allowed_ips[128]; + ConVar sv_set_steam_id_ips = FindConVar("sv_set_steam_id_ips"); + if (sv_set_steam_id_ips != null) + { + sv_set_steam_id_ips.GetString(allowed_ips, sizeof(allowed_ips)); + if (StrEqual(sIP, allowed_ips)) + { + g_bWebclient[client] = true; + //this works fine with one webclient only existing. + char webclientName[64]; + GetConVarString(FindConVar("sv_webclient_name"), webclientName, sizeof(webclientName)); + SetClientName(client, webclientName); + SendWebclientNameToSignaling(webclientName); + } + } +} + +public void OnClientAuthorized(int client, const char[] auth) +{ + if (IsFakeClient(client)) + { + return; + } + + SetClientNoSteam(client, false); + if (!PM_IsPlayerSteam(client)) + { + SetClientNoSteam(client, true); + //LogMessage("here in onauthorized client: %N", client); + //setting it too early does not work, so some delay needed. + CreateTimer(10.0, Timer_SendVoiceInit, GetClientSerial(client)); + CreateTimer(20.0, Timer_SendVoiceInit, GetClientSerial(client)); + CreateTimer(30.0, Timer_SendVoiceInit, GetClientSerial(client)); + CreateTimer(40.0, Timer_SendVoiceInit, GetClientSerial(client)); + CreateTimer(50.0, Timer_SendVoiceInit, GetClientSerial(client)); + CreateTimer(60.0, Timer_SendVoiceInit, GetClientSerial(client)); + } +} + +public Action CCC_OnChatMessage(int client, int author, const char[] message) +{ + if (!g_bWebclient[client]) + { + return Plugin_Continue; + } + int index = FindCharInString(message, '"', false); + int index1 = FindCharInString(message, ';', false); + if (index != -1 || index1 != -1) + { + return Plugin_Handled; + } + return Plugin_Continue; +} + +public Action Timer_SendVoiceInit(Handle timer, int Serial) +{ + int client; + if ((client = GetClientFromSerial(Serial)) == 0) + { + return Plugin_Handled; + } + if (IsValidClient(client)) + { + SendCeltVoiceInit(client); + } + return Plugin_Handled; +} + +/** + * Polls the signaling server for the current webclient controller's real IP. + * If the IP has changed since the last + * check and a webclient player is currently connected, forces them to + * reconnect with the new password via ClientCommand. + **/ +public void PollWebclientCurrentIp() +{ + Handle hRequest = SteamWorks_CreateHTTPRequest(k_EHTTPMethodGET, "http://127.0.0.1:3000/webclient-current-ip"); + if (hRequest == null) + { + return; + } + + if (!SteamWorks_SetHTTPCallbacks(hRequest, OnWebclientCurrentIpReceived) || + !SteamWorks_SendHTTPRequest(hRequest)) + { + delete hRequest; + } +} + +public int OnWebclientCurrentIpReceived(Handle hRequest, bool bFailure, bool bRequestSuccessful, + EHTTPStatusCode eStatusCode, any data) +{ + if (bFailure || !bRequestSuccessful || eStatusCode != k_EHTTPStatusCode200OK) + { + delete hRequest; + return 0; + } + + int bodySize; + bool gotSize = SteamWorks_GetHTTPResponseBodySize(hRequest, bodySize); + + char newIp[64]; + newIp[0] = '\0'; + + if (gotSize && bodySize > 0 && bodySize < sizeof(newIp)) + { + SteamWorks_GetHTTPResponseBodyData(hRequest, newIp, bodySize); + } + + delete hRequest; + + if (newIp[0] == '\0') + { + return 0; + } + + if (StrEqual(newIp, g_sLastWebclientIp)) + { + return 0; + } + + for (int i = 1; i <= MaxClients; i++) + { + if (IsValidClient(i) && g_bWebclient[i]) + { + strcopy(g_sLastWebclientIp, sizeof(g_sLastWebclientIp), newIp); + LogMessage("Forcing webclient reconnect for client %N with new IP: %s", i, newIp); + ClientCommand(i, "retry"); + break; + } + } + return 0; +} + +public EConnect OnClientPreConnectEx(const char[] sName, char sPassword[255], const char[] sIP, const char[] sSteam32ID, char sRejectReason[255]) +{ + char allowedIp[64]; + ConVar sv_set_steam_id_ips = FindConVar("sv_set_steam_id_ips"); + if (sv_set_steam_id_ips != null) + { + sv_set_steam_id_ips.GetString(allowedIp, sizeof(allowedIp)); + //this is to handle that the connect extension receives the password parameter for the webclient as its real connecting IP. + //works both for the client command retry and for the case that somebody presses the connect button in the clients Menu as the same password + //is applied again. + if (StrEqual(sIP, allowedIp) && strlen(g_sLastWebclientIp) > 0) + { + strcopy(sPassword, 255, g_sLastWebclientIp); + LogMessage("Backfilled empty password for webclient with cached IP: %s", g_sLastWebclientIp); + } + } + // ET_LowEvent takes the LOWEST value returned across all plugins hooking this forward. + //this plugin returns 1 (Accept), meanwhile the reserved slot plugin still might return 0 (reject) or -1 (async) to overrule the decision from this return value. + return k_OnClientPreConnectEx_Accept; +} + +stock bool IsValidClient(int client) +{ + if (client > 0 && client <= MaxClients && IsClientConnected(client) && IsClientInGame(client)) + return true; + return false; +}