Skip to content

Commit

Permalink
Fix spectator warning for ET:Legacy
Browse files Browse the repository at this point in the history
  • Loading branch information
Ch40zz committed Sep 25, 2024
1 parent de833a8 commit 3e79c43
Show file tree
Hide file tree
Showing 3 changed files with 104 additions and 25 deletions.
6 changes: 4 additions & 2 deletions CCHookReloaded/dllmain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1093,8 +1093,10 @@ intptr_t __cdecl hooked_vmMain(intptr_t id, intptr_t a1, intptr_t a2, intptr_t a
// Spectator Warning
if (cfg.spectatorWarning)
{
std::vector<std::string> spectatorNames;
if (tools::GatherSpectatorInfo(spectatorNames) && !spectatorNames.empty())
static std::vector<std::string> spectatorNames;
tools::GatherSpectatorInfo(spectatorNames);

if (!spectatorNames.empty())
{
ui::DrawText(320.0f, 90.0f, 0.20f, 0.20f, colorRed, XorString("WARNING - Spectator:"),
0.0f, 0, ITEM_TEXTSTYLE_SHADOWED, ITEM_ALIGN_CENTER, &media.limboFont1);
Expand Down
25 changes: 23 additions & 2 deletions CCHookReloaded/pch.h
Original file line number Diff line number Diff line change
Expand Up @@ -523,7 +523,7 @@ typedef enum
NUM_BUTTONS
} kbuttons_t;

typedef enum
enum class netadrtype_t
{
NA_BOT,
NA_BAD, // an address lookup failed
Expand All @@ -532,7 +532,7 @@ typedef enum
NA_IP,
NA_IPX,
NA_BROADCAST_IPX
} netadrtype_t;
};

typedef struct
{
Expand All @@ -544,6 +544,27 @@ typedef struct
unsigned short port;
} netadr_t;

enum class netadrtype_legacy_t : uint16_t
{
NA_BAD = 0, ///< an address lookup failed
NA_BOT,
NA_LOOPBACK,
NA_BROADCAST,
NA_IP,
NA_IP6,
NA_MULTICAST6,
NA_UNSPEC
};

typedef struct
{
netadrtype_legacy_t type;
byte ip[4];
byte ip6[16];
uint16_t port;
uint64_t scope_id; ///< Needed for IPv6 link-local addresses
} netadr_legacy_t;

#pragma pack(push, 1)
/*struct etpro_command
{
Expand Down
98 changes: 77 additions & 21 deletions CCHookReloaded/tools.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -209,38 +209,92 @@ namespace tools
cg_snapshot.ps.pm_flags & PMF_FOLLOW)
return false;

// Create socket if needed (once)
static SOCKET sock = INVALID_SOCKET;
if (sock == INVALID_SOCKET)
// Get current network destination and fix it up for localhost if needed
uint16_t port;
ADDRESS_FAMILY family;
size_t addressSize;
uint8_t address[32];

if (off::cur.IsEtLegacy())
{
sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (sock != INVALID_SOCKET)
const netadr_legacy_t* remoteAddress = (netadr_legacy_t*)off::cur.remoteAddress();
switch (remoteAddress->type)
{
// Make socket non-blocking for obvious reasons
u_long mode = 1;
ioctlsocket(sock, FIONBIO, &mode);
case netadrtype_legacy_t::NA_IP:
family = AF_INET;
port = remoteAddress->port;
addressSize = sizeof(remoteAddress->ip);
memcpy(address, remoteAddress->ip, addressSize);
break;
case netadrtype_legacy_t::NA_IP6:
family = AF_INET6;
port = remoteAddress->port;
addressSize = sizeof(remoteAddress->ip6);
memcpy(address, remoteAddress->ip6, addressSize);
break;
default:
family = AF_INET;
vmCvar_t net_port; // localhost port
DoSyscall(CG_CVAR_REGISTER, &net_port, XorString("net_port"), XorString("27960"), 0);
port = htons(net_port.integer);
addressSize = sizeof(remoteAddress->ip);
*(uint32_t*)address = 0x0100007F;
break;
}
}
else
{
const netadr_t* remoteAddress = off::cur.remoteAddress();
switch (remoteAddress->type)
{
case netadrtype_t::NA_IP:
family = AF_INET;
port = remoteAddress->port;
addressSize = sizeof(remoteAddress->ip);
memcpy(address, remoteAddress->ip, addressSize);
break;
case netadrtype_t::NA_IPX:
family = AF_IPX;
port = remoteAddress->port;
addressSize = sizeof(remoteAddress->ipx);
memcpy(address, remoteAddress->ipx, addressSize);
break;
default:
family = AF_INET;
vmCvar_t net_port; // localhost port
DoSyscall(CG_CVAR_REGISTER, &net_port, XorString("net_port"), XorString("27960"), 0);
port = htons(net_port.integer);
addressSize = sizeof(remoteAddress->ip);
*(uint32_t*)address = 0x0100007F;
break;
}
}

// localhost port
vmCvar_t net_port;
DoSyscall(CG_CVAR_REGISTER, &net_port, XorString("net_port"), XorString("27960"), 0);

// Get current network destination and fix it up for localhost if needed
netadr_t *remoteAddress = off::cur.remoteAddress();
const uint32_t ipAddress = *(uint32_t*)remoteAddress->ip ? *(uint32_t*)remoteAddress->ip : 0x0100007F;
const uint16_t port = remoteAddress->port ? remoteAddress->port : htons(net_port.integer);
static SOCKET sock = INVALID_SOCKET;

// Send server status request every 500 ms
static int timeout_ms = 0;
if ((timeout_ms -= cg_frametime) <= 0)
{
timeout_ms = 500;

// Re-Create socket if needed

if (sock != INVALID_SOCKET)
closesocket(sock);

sock = socket(family, SOCK_DGRAM, IPPROTO_UDP);
if (sock != INVALID_SOCKET)
{
// Make socket non-blocking for obvious reasons
u_long mode = 1;
ioctlsocket(sock, FIONBIO, &mode);
}

sockaddr_in sockAddr;
sockAddr.sin_family = AF_INET;
sockAddr.sin_addr.s_addr = ipAddress;
sockAddr.sin_family = family;
sockAddr.sin_port = port;
memcpy(&sockAddr.sin_addr, address, addressSize);

// UDP messages always arrive (if they arrive) in the exact same size as sent
sendto(sock, XorString(NET_STATUS_REQUEST), sizeof(NET_STATUS_REQUEST)-1, 0, (sockaddr*)&sockAddr, sizeof(sockAddr));
Expand All @@ -254,23 +308,25 @@ namespace tools

// UDP messages always arrive (if they arrive) in the exact same size as sent
char buffer[4096];
int read = recvfrom(sock, buffer, sizeof(buffer), 0, (sockaddr*)&sockAddr, &fromlen);
int read = recvfrom(sock, buffer, sizeof(buffer) - 1, 0, (sockaddr*)&sockAddr, &fromlen);
if (read <= 0)
return false;

buffer[read] = '\0';

if (sockAddr.sin_addr.s_addr != ipAddress || sockAddr.sin_port != port)
if (sockAddr.sin_family != family || sockAddr.sin_port != port || memcmp(&sockAddr.sin_addr, address, addressSize))
return false;

if (memcmp(buffer, XorString(NET_STATUS_RESPONSE), sizeof(NET_STATUS_RESPONSE)-1))
if (memcmp(buffer, XorString(NET_STATUS_RESPONSE), sizeof(NET_STATUS_RESPONSE) - 1))
return false;

// Parse the server info to find all spectators.
// A spectator will always inherit the XP numbers of the spectated player.
// Because XP numbers are rather unique, this can detect spectators.
// To be 100% certain, we should filter out existing players.

spectatorNames.clear();

std::stringstream playersstream(buffer + sizeof(NET_STATUS_RESPONSE)-1);

std::string playerStats;
Expand Down

0 comments on commit 3e79c43

Please sign in to comment.