- 4,804
- 6,475
Если вы не играете на samp-rp и у вас уже есть реконнект, то можете пропустить эту тему.
Фишка данного реконнекта в том, что он позволяет переподключиться к серверам СРП после кика, и для этого не придется использовать сраунчер или сворачивать игру и кликать по серверу в обычном лаунчере - udp пропинговка встроенна в плагин!
Использование 1: /rej <time> - переподключиться к серверу с заданным временем. Время указывается в секундах
Использование 2: /rej <time> <nick> - то же, что и выше, но со сменой ника.
Команду так же можно вызывать из консоли SF. Пример: rej <time> | rej <time> <nick>
P.S. На других серверах реконнект тоже работает.
Фишка данного реконнекта в том, что он позволяет переподключиться к серверам СРП после кика, и для этого не придется использовать сраунчер или сворачивать игру и кликать по серверу в обычном лаунчере - udp пропинговка встроенна в плагин!
Использование 1: /rej <time> - переподключиться к серверу с заданным временем. Время указывается в секундах
Использование 2: /rej <time> <nick> - то же, что и выше, но со сменой ника.
Команду так же можно вызывать из консоли SF. Пример: rej <time> | rej <time> <nick>
P.S. На других серверах реконнект тоже работает.
C++:
#define _SILENCE_STDEXT_HASH_DEPRECATION_WARNINGS
#include <windows.h>
#include <string>
#include <assert.h>
#include <process.h>
#include <regex>
#include <thread>
#include <atomic>
#include <future>
#pragma comment(lib, "WS2_32")
#include "SAMPFUNCS_API.h"
#include "game_api\game_api.h"
SAMPFUNCS *SF = new SAMPFUNCS();
template <typename T>
union byteValue {
T value;
byte bytes[sizeof(T)];
};
void UdpThread(std::string ip, byte ip_0, byte ip_1, byte ip_2, byte ip_3, WORD port)
{
WSADATA wsaData;
SOCKET SendRecvSocket; // сокет для приема и передачи
sockaddr_in ServerAddr; // это будет адрес сервера и клиентов
char query[64]; // буфер отправки
// Initialize Winsock
WSAStartup(MAKEWORD(2, 2), &wsaData);
// Create a SOCKET for connecting to server
SendRecvSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
ServerAddr.sin_family = AF_INET;
ServerAddr.sin_addr.s_addr = inet_addr(ip.c_str());
ServerAddr.sin_port = htons(port);
connect(SendRecvSocket, (struct sockaddr *)&ServerAddr, sizeof(sockaddr));
query[0] = 'S';
query[1] = 'A';
query[2] = 'M';
query[3] = 'P';
query[4] = ip_0;
query[5] = ip_1;
query[6] = ip_2;
query[7] = ip_3;
byteValue<WORD> _port;
_port.value = port;
query[8] = _port.bytes[0];
query[9] = _port.bytes[1];
query[11] = '\0';
// отправляем запрос на сервер
for (int i = 0; i < 3; ++i) {
query[10] = 'p';
sendto(SendRecvSocket, query, strlen(query), 0, (sockaddr *)&ServerAddr, sizeof(ServerAddr));
query[10] = 'i';
sendto(SendRecvSocket, query, strlen(query), 0, (sockaddr *)&ServerAddr, sizeof(ServerAddr));
query[10] = 'r';
sendto(SendRecvSocket, query, strlen(query), 0, (sockaddr *)&ServerAddr, sizeof(ServerAddr));
Sleep(250);
}
closesocket(SendRecvSocket);
WSACleanup();
}
DWORD g_timer = 0;
const std::regex REJ_NICK(R"(\s*(\d+)\s*(.{3,26})\s*)");
const std::regex REJ_TIME(R"(\s*(\d+)\s*)");
void CALLBACK cmd(std::string param)
{
std::smatch match;
if (std::regex_match(param, match, REJ_NICK)) {
SF->getSAMP()->disconnect(100);
SF->getSAMP()->getPlayers()->SetLocalPlayerName(match[2].str().c_str());
g_timer = atoi(match[1].str().c_str()) * 1000 + GetTickCount();
}
else if (std::regex_match(param, match, REJ_TIME)) {
SF->getSAMP()->disconnect(100);
g_timer = atoi(match[1].str().c_str()) * 1000 + GetTickCount();
}
else SF->Log("[CoolReconnect]: Can't match '%s'", param.c_str());
}
void CALLBACK mainloop()
{
static bool init = false;
if (!init)
{
if (GAME == nullptr)
return;
if (GAME->GetSystemState() != eSystemState::GS_PLAYING_GAME)
return;
if (!SF->getSAMP()->IsInitialized())
return;
SF->registerConsoleCommand("rej", cmd);
SF->getSAMP()->registerChatCommand("rej", cmd);
SF->getSAMP()->setChatCommandDescription("rej", "{FFFFAAAA}see help for console rej");
SF->setConsoleCommandDescription("rej", "Reconnect to server.\n\
{FFFFFFFF}Can get 2 params:\n\
{FFFFFFFF}--1: time\n\
{FFFFFFFF}--2: nick\n\n\
{FFAAFFAA}Example: rej 15\n\
{FFAAFFAA}Example: rej 15 SR_team\n");
init = true;
}
else if (g_timer)
{
static bool UdpReconnect = false;
if (g_timer - GetTickCount() < 5000 && !UdpReconnect) {
char newIp[64];
WSADATA wsaData;
WSAStartup(MAKEWORD(1, 1), &wsaData);
struct hostent *he = gethostbyname(SF->getSAMP()->getInfo()->szIP);
if (he != NULL) {
strcpy(newIp, inet_ntoa(*((struct in_addr *) he->h_addr_list[0])));
}
WSACleanup();
byte ip_0 = 127;
byte ip_1 = 0;
byte ip_2 = 0;
byte ip_3 = 1;
if (sscanf(newIp, "%d.%d.%d.%d", &ip_0, &ip_1, &ip_2, &ip_3)) {
std::thread thr(UdpThread, std::string(newIp), ip_0, ip_1, ip_2, ip_3, SF->getSAMP()->getInfo()->ulPort);
thr.detach();
UdpReconnect = true;
}
}
if (g_timer > GetTickCount())
return;
SF->getSAMP()->getInfo()->RestartGame();
SF->getSAMP()->getInfo()->iGameState = GAMESTATE_WAIT_CONNECT;
g_timer = 0;
UdpReconnect = false;
}
}
BOOL APIENTRY DllMain(HMODULE hModule, DWORD dwReasonForCall, LPVOID lpReserved)
{
switch (dwReasonForCall)
{
case DLL_PROCESS_ATTACH:
SF->initPlugin(mainloop, hModule);
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}