diff --git a/simulate_ze_server/python/move_text_to_simulate_server.py b/simulate_ze_server/python/move_text_to_simulate_server.py new file mode 100644 index 00000000..bdec0cbf --- /dev/null +++ b/simulate_ze_server/python/move_text_to_simulate_server.py @@ -0,0 +1,10 @@ +#!/usr/bin/python3 +def main(): + with open("/home/gameservers/css_ze/cstrike/addons/sourcemod/logs/simulate.txt", "r") as file: + lines = [line.rstrip() for line in file] + + with open('/home/gameservers/css_simulate_ze/cstrike/addons/sourcemod/logs/simulate.txt', 'w') as fp: + fp.write('\n'.join(lines)) + +if __name__ == '__main__': + main() diff --git a/simulate_ze_server/scripting/simulate_ze_server.sp b/simulate_ze_server/scripting/simulate_ze_server.sp new file mode 100644 index 00000000..2c4b94f2 --- /dev/null +++ b/simulate_ze_server/scripting/simulate_ze_server.sp @@ -0,0 +1,212 @@ +#pragma semicolon 1 + +#include +#include + +int server_ports[2] = {27015, 27075}; //server ports: ze server, simulated server. +int g_iServerPort; +int g_iClientIndexUserIDMapping[MAXPLAYERS + 1]; + +//---------------------------------------------------------------------------------------------------- +// Purpose: +//---------------------------------------------------------------------------------------------------- +public Plugin myinfo = +{ + name = "info from the ze server", + author = "jenz", + description = "just copies maps, hostname and client names info from the ze server", + version = "1.0.0" +}; + +public void OnPluginEnd() +{ + for(int i = 1; i <= MaxClients; i++) + { + if(IsValidClient(i) && IsFakeClient(i)) + { + KickClient(i, "Disconnect by user."); + } + } +} + +public void OnPluginStart() +{ + g_iServerPort = GetConVarInt(FindConVar("hostport")); + if (g_iServerPort == server_ports[0]) + { + CreateTimer(15.0, update_info_over_txt, _, TIMER_REPEAT); + } + else if (g_iServerPort == server_ports[1]) + { + CreateTimer(GetRandomFloat(5.0, 25.0), read_info_over_txt); + } +} + +public Action read_info_over_txt(Handle timer, any data) +{ + new Handle:fileHandle = OpenFile("/addons/sourcemod/logs/simulate.txt", "r"); + char lineBuffer[2048]; + int count = 0; + + int current_ClientUserID_iteration[MAXPLAYERS + 1]; + + bool already_created_fakeClient = false; + + while(!IsEndOfFile(fileHandle) && ReadFileLine(fileHandle, lineBuffer, sizeof(lineBuffer))) + { + TrimString(lineBuffer); + if (count == 0) //mapname + { + char mapname[256]; + GetCurrentMap(mapname, sizeof(mapname)); + if (!StrEqual(mapname, lineBuffer)) + { + ForceChangeLevel(lineBuffer, ""); + break; + } + } + else if (count == 1) //hostname + { + static Handle hHostName; + if((hHostName = FindConVar("hostname")) == INVALID_HANDLE) + return Plugin_Handled; + SetConVarString(hHostName, lineBuffer, false, false); + } + else //reading clientUserID, client frag and playername + { + //index 0 = ClientUserID, index 1 = client frags, index 2 = client user name. + char[][] sPart = new char[3][256]; + ExplodeString(lineBuffer, " ", sPart, 3, 256); + int ClientUserID = StringToInt(sPart[0]); + + bool does_client_user_id_exist = false; + for (int i = 0; i <= MaxClients; i++) + { + //the clients on the simulate server will always first exist after CreateFakeClient so this approach should be safe. + if (IsValidClient(i) && !IsClientSourceTV(i) && g_iClientIndexUserIDMapping[i] == ClientUserID) + { + does_client_user_id_exist = true; + break; + } + } + + if (!does_client_user_id_exist && !already_created_fakeClient) + { + //User ID is new, so lets create the FakeClient. + int iIndex = CreateFakeClient(sPart[2]); + + if(iIndex < 1 || iIndex > MaxClients) + break; + + SetEntityFlags(iIndex, FL_CLIENT); + DispatchKeyValue(iIndex, "classname", "player"); + DispatchSpawn(iIndex); + + AdminId FakeAdmin = CreateAdmin(); + SetAdminFlag(FakeAdmin, Admin_Custom6, true); + SetUserAdmin(iIndex, FakeAdmin, true); + + g_iClientIndexUserIDMapping[iIndex] = ClientUserID; + already_created_fakeClient = true; + } + + //updating the clients frags and username based on the ClientUserID. + for (int i = 0; i <= MaxClients; i++) + { + if (IsValidClient(i) && !IsClientSourceTV(i) && g_iClientIndexUserIDMapping[i] == ClientUserID) + { + int clientFrag = StringToInt(sPart[1]); + SetEntProp(i, Prop_Data, "m_iFrags", clientFrag); + SetClientName(i, sPart[2]); + //indicating that the client still exists right now. + current_ClientUserID_iteration[i] = ClientUserID; + break; + } + } + } + count++; + } + CloseHandle(fileHandle); + + //kicking clients whos UserID is not connected on ze anymore. + for (int i = 0; i <= MaxClients; i++) + { + if (IsValidClient(i) && !IsClientSourceTV(i)) + { + bool does_UserID_still_exist = false; + for (int j = 0; j <= MaxClients; j++) + { + //for every user in g_iClientIndexUserIDMapping does the userID exist in the current iteration still. + if (IsValidClient(j) && !IsClientSourceTV(j) && g_iClientIndexUserIDMapping[i] == current_ClientUserID_iteration[j]) + { + does_UserID_still_exist = true; + break; + } + } + if (!does_UserID_still_exist) + { + g_iClientIndexUserIDMapping[i] = -1; + KickClient(i, "Disconnect by user."); + } + } + } + CreateTimer(GetRandomFloat(5.0, 25.0), read_info_over_txt); + return Plugin_Handled; +} + +public Action update_info_over_txt(Handle timer, any data) +{ + //sending map name, hostname and player names to the simulate server from ze server. + char g_cMapname[256]; + GetCurrentMap(g_cMapname, sizeof(g_cMapname)); + + static Handle hHostName; + if((hHostName = FindConVar("hostname")) == INVALID_HANDLE) + return Plugin_Handled; + char hostname[256]; + GetConVarString(hHostName, hostname, sizeof(hostname)); + + char msg[2048]; + Format(msg, sizeof(msg), "%s\n%s\n", g_cMapname, hostname); + //cleaning the file so it only contains mapname and hostname + new Handle:testFile = OpenFile("/addons/sourcemod/logs/simulate.txt", "w"); + WriteFileLine(testFile, msg); + CloseHandle(testFile); + + Format(msg, sizeof(msg), ""); + + for (int i = 0; i < MaxClients; i++) + { + if (IsValidClient(i) && !IsClientSourceTV(i)) + { + int frags = GetClientFrags(i); + //GetClientUserId is the only consistent thing for fakeclients. + Format(msg, sizeof(msg), "%d %i %N\n", GetClientUserId(i), frags, i); + + new Handle:testFile_l = OpenFile("/addons/sourcemod/logs/simulate.txt", "a"); + WriteFileLine(testFile_l, msg); + CloseHandle(testFile_l); + } + } + return Plugin_Handled; +} + +//sending players over to the actual ze server if its the simulated server. +public void OnClientPostAdminCheck(int client) +{ + if (g_iServerPort != server_ports[1]) + { + return; + } + if (!IsFakeClient(client) && (!IsClientSourceTV(client))) + { + ClientCommand(client, "redirect ze.unloze.com:27015"); + } +} + +stock bool IsValidClient(int client) +{ + if (client > 0 && client <= MaxClients && IsClientConnected(client) && IsClientInGame(client)) + return true; + return false; +} diff --git a/simulate_ze_server/systemctl/move_to_simulate.service b/simulate_ze_server/systemctl/move_to_simulate.service new file mode 100644 index 00000000..00e6e4f5 --- /dev/null +++ b/simulate_ze_server/systemctl/move_to_simulate.service @@ -0,0 +1,10 @@ +[Unit] +Description=Moves info from ze to the simulate server + +[Service] +Type=simple +User=gameservers +WorkingDirectory=/home/gameservers/udp_director +ExecStart=/home/gameservers/udp_director/move_text_to_simulate_server.py +Restart=always +RestartSec=10s