| 2999 | } |
| 3000 | |
| 3001 | void CServer::UpdateDebugDummies(bool ForceDisconnect) |
| 3002 | { |
| 3003 | if(m_PreviousDebugDummies == g_Config.m_DbgDummies && !ForceDisconnect) |
| 3004 | return; |
| 3005 | |
| 3006 | g_Config.m_DbgDummies = std::clamp(g_Config.m_DbgDummies, 0, MaxClients()); |
| 3007 | for(int DummyIndex = 0; DummyIndex < maximum(m_PreviousDebugDummies, g_Config.m_DbgDummies); ++DummyIndex) |
| 3008 | { |
| 3009 | const bool AddDummy = !ForceDisconnect && DummyIndex < g_Config.m_DbgDummies; |
| 3010 | const int ClientId = MaxClients() - DummyIndex - 1; |
| 3011 | CClient &Client = m_aClients[ClientId]; |
| 3012 | if(AddDummy && m_aClients[ClientId].m_State == CClient::STATE_EMPTY) |
| 3013 | { |
| 3014 | NewClientCallback(ClientId, this, false); |
| 3015 | Client.m_DebugDummy = true; |
| 3016 | |
| 3017 | // See https://en.wikipedia.org/wiki/Unique_local_address |
| 3018 | Client.m_DebugDummyAddr.type = NETTYPE_IPV6; |
| 3019 | Client.m_DebugDummyAddr.ip[0] = 0xfd; |
| 3020 | // Global ID (40 bits): random |
| 3021 | secure_random_fill(&Client.m_DebugDummyAddr.ip[1], 5); |
| 3022 | // Subnet ID (16 bits): constant |
| 3023 | Client.m_DebugDummyAddr.ip[6] = 0xc0; |
| 3024 | Client.m_DebugDummyAddr.ip[7] = 0xde; |
| 3025 | // Interface ID (64 bits): set to client ID |
| 3026 | Client.m_DebugDummyAddr.ip[8] = 0x00; |
| 3027 | Client.m_DebugDummyAddr.ip[9] = 0x00; |
| 3028 | Client.m_DebugDummyAddr.ip[10] = 0x00; |
| 3029 | Client.m_DebugDummyAddr.ip[11] = 0x00; |
| 3030 | uint_to_bytes_be(&Client.m_DebugDummyAddr.ip[12], ClientId); |
| 3031 | // Port: random like normal clients |
| 3032 | Client.m_DebugDummyAddr.port = secure_rand_below(65535 - 1024) + 1024; |
| 3033 | net_addr_str(&Client.m_DebugDummyAddr, Client.m_aDebugDummyAddrString.data(), Client.m_aDebugDummyAddrString.size(), true); |
| 3034 | net_addr_str(&Client.m_DebugDummyAddr, Client.m_aDebugDummyAddrStringNoPort.data(), Client.m_aDebugDummyAddrStringNoPort.size(), false); |
| 3035 | |
| 3036 | GameServer()->OnClientConnected(ClientId, nullptr); |
| 3037 | Client.m_State = CClient::STATE_INGAME; |
| 3038 | str_format(Client.m_aName, sizeof(Client.m_aName), "Debug dummy %d", DummyIndex + 1); |
| 3039 | GameServer()->OnClientEnter(ClientId); |
| 3040 | } |
| 3041 | else if(!AddDummy && Client.m_DebugDummy) |
| 3042 | { |
| 3043 | DelClientCallback(ClientId, "Dropping debug dummy", this); |
| 3044 | } |
| 3045 | |
| 3046 | if(AddDummy && Client.m_DebugDummy) |
| 3047 | { |
| 3048 | CNetObj_PlayerInput Input = {0}; |
| 3049 | Input.m_Direction = (ClientId & 1) ? -1 : 1; |
| 3050 | Client.m_aInputs[0].m_GameTick = Tick() + 1; |
| 3051 | mem_copy(Client.m_aInputs[0].m_aData, &Input, minimum(sizeof(Input), sizeof(Client.m_aInputs[0].m_aData))); |
| 3052 | Client.m_LatestInput = Client.m_aInputs[0]; |
| 3053 | Client.m_CurrentInput = 0; |
| 3054 | } |
| 3055 | } |
| 3056 | |
| 3057 | m_PreviousDebugDummies = ForceDisconnect ? 0 : g_Config.m_DbgDummies; |
| 3058 | } |
nothing calls this directly
no test coverage detected