Files
ToyBattlesHQ/CastServer/include/Structures/PlayerPositionFromClient.h
2025-09-20 07:12:50 -07:00

223 lines
6.8 KiB
C++

#ifndef PLAYER_POSITION_STRUCTURE_H
#define PLAYER_POSITION_STRUCTURE_H
#include <cstdint>
#include <directxmath/DirectXPackedVector.h>
#include "AntiCheat/Event.h"
#include "Macros.h"
namespace Cast
{
namespace Structures
{
inline bool isBadPosition(auto position)
{
std::uint32_t rawVal = reinterpret_cast<std::uint32_t&>(position);
if (rawVal == -2147483648 || rawVal == 2139095040)
return true;
uint16_t rawBits = *reinterpret_cast<uint16_t*>(&position);
uint16_t exponentMask = 0x7C00;
uint16_t fractionMask = 0x03FF;
return (rawBits & exponentMask) == exponentMask && (rawBits & fractionMask) != 0 ||
(rawBits & exponentMask) == exponentMask && (rawBits & fractionMask) == 0;
}
inline bool isNaNOrInfinity(float value)
{
return std::isnan(value) || value == -2147483648 || value == 2139095040;
}
inline std::int32_t halfToFloat(std::uint16_t half)
{
std::int32_t exponent = (half >> 10) & 0x1F;
std::int32_t sign = half >> 15;
std::int32_t mantissa = half & 0x3FF;
if (!exponent)
{
if ((half & 0x3FF) == 0)
return sign << 31;
do
{
mantissa *= 2;
--exponent;
} while ((mantissa & 0x400) == 0);
++exponent;
mantissa &= ~0x400u;
return ((exponent + 112) << 23) | ((mantissa | (sign << 18)) << 13);
}
if (exponent != 31)
return ((exponent + 112) << 23) | ((mantissa | (sign << 18)) << 13);
if ((half & 0x3FF) != 0)
return (mantissa | (sign << 18) | 0x3FC00) << 13; // NaN case
else
return (sign << 31) | 0x7F800000; // Infinity case
}
PACK_PUSH(1)
struct PositionStruct
{
DirectX::PackedVector::HALF positionX{};
DirectX::PackedVector::HALF positionY{};
DirectX::PackedVector::HALF positionZ{};
bool isBadPos()
{
if (isNaNOrInfinity(halfToFloat(positionX)) || isNaNOrInfinity(halfToFloat(positionY)) || isNaNOrInfinity(halfToFloat(positionZ))) return true;
return isBadPosition(positionX) || isBadPosition(positionY) || isBadPosition(positionZ);
}
};
PACK_POP()
PACK_PUSH(1)
struct DirectionStruct
{
DirectX::PackedVector::HALF directionX{};
DirectX::PackedVector::HALF directionY{};
DirectX::PackedVector::HALF directionZ{};
bool isBadDir()
{
if (isNaNOrInfinity(halfToFloat(directionX)) || isNaNOrInfinity(halfToFloat(directionY)) || isNaNOrInfinity(halfToFloat(directionZ))) return true;
return isBadPosition(directionX) || isBadPosition(directionY) || isBadPosition(directionZ);
}
};
PACK_POP()
PACK_PUSH(1)
struct BulletsStruct
{
DirectX::PackedVector::HALF bullet1{};
DirectX::PackedVector::HALF bullet2{};
DirectX::PackedVector::HALF bullet3{};
DirectX::PackedVector::HALF bullet4{};
bool isBadBullets()
{
if (isNaNOrInfinity(halfToFloat(bullet1)) || isNaNOrInfinity(halfToFloat(bullet2)) || isNaNOrInfinity(halfToFloat(bullet3))
|| isNaNOrInfinity(halfToFloat(bullet4))) return true;
return isBadPosition(bullet1) || isBadPosition(bullet2) || isBadPosition(bullet3) || isBadPosition(bullet4);
}
};
PACK_POP()
PACK_PUSH(1)
struct JumpStruct
{
DirectX::PackedVector::HALF jump1;
DirectX::PackedVector::HALF jump2;
bool isBadJump()
{
if (isNaNOrInfinity(halfToFloat(jump1)) || isNaNOrInfinity(halfToFloat(jump2))) return true;
return isBadPosition(jump1) || isBadPosition(jump2);
}
};
PACK_POP()
PACK_PUSH(1)
struct ClientPlayerInfoBasic
{
PositionStruct position;
DirectionStruct direction;
std::uint32_t matchTick{};
std::uint32_t animation1 : 7 = 0;
std::uint32_t animation2 : 6 = 0;
std::uint32_t weapon : 4 = 0;
std::uint32_t rotation : 9 = 0;
std::uint32_t unknown : 6 = 0;
bool isBad()
{
return position.isBadPos() || direction.isBadDir();
}
};
PACK_POP()
PACK_PUSH(1)
struct ClientPlayerInfoJump
{
ClientPlayerInfoBasic playerPositionBasic;
JumpStruct jumpStruct{};
bool isBad()
{
return playerPositionBasic.isBad() || jumpStruct.isBadJump();
}
};
PACK_POP()
PACK_PUSH(1)
struct ClientPlayerInfoBullet
{
ClientPlayerInfoBasic playerPositionBasic;
BulletsStruct bulletStruct{};
bool isBad()
{
return playerPositionBasic.isBad() || bulletStruct.isBadBullets();
}
};
PACK_POP()
PACK_PUSH(1)
struct ClientPlayerInfoComplete
{
ClientPlayerInfoBasic playerPositionBasic;
BulletsStruct bulletStruct{};
JumpStruct jumpStruct{};
bool isBad()
{
return playerPositionBasic.isBad() || bulletStruct.isBadBullets() || jumpStruct.isBadJump();
}
};
PACK_POP()
PACK_PUSH(1)
struct SinglePlayerJoinInfo
{
char u0[16]{};
Main::Structures::UniqueId uid;
std::uint32_t unknown{};
};
PACK_POP()
PACK_PUSH(1)
struct SinglePlayerJoinInfoResponse
{
Main::Structures::UniqueId uid;
std::uint32_t u0 : 20 = 0; // This may be zombie mode weapon ID or HP given by client, no idea about it -- could be related to special melee weapon in zombie mode
std::uint32_t mode : 5 = 0; // client checks whether the mode is zombie for some reason
std::uint32_t playerState : 4 = 0;
};
PACK_POP()
PACK_PUSH(1)
struct PlayerRespawnPosition
{
std::uint16_t x{};
std::uint16_t y{};
std::uint16_t z{};
std::uint16_t w{};
Main::Structures::UniqueId targetUniqueId{};
PlayerRespawnPosition& operator=(const Cast::Structures::PositionStruct& pos)
{
x = pos.positionX;
z = pos.positionZ;
y = pos.positionY;
return *this;
}
};
PACK_POP()
}
}
#endif