ReSemiclip/src/main.cpp
2024-05-18 22:56:31 +05:00

729 lines
18 KiB
C++

#include "precompiled.h"
cvar_t cv_resemiclip_version = { "resemiclip_version", Plugin_info.version, FCVAR_SERVER | FCVAR_EXTDLL, 0, nullptr };
CGamePlayer g_Players[MAX_CLIENTS];
CConfig g_Config;
CGameData g_GameData;
CBaseEntity *g_pVirtualGrenade;
bool bInitialized = false;
bool bActivated = false;
struct {
const char *classname;
CBaseEntity *&ptr;
}
g_RegVirtualTable[] = {
{ "grenade", g_pVirtualGrenade }
};
int OnMetaAttach()
{
Load_Config();
g_engfuncs.pfnCvar_RegisterVariable(&cv_resemiclip_version);
REG_SVR_COMMAND("semiclip_option", SVR_SemiclipOption);
g_RehldsHookchains->SV_CreatePacketEntities()->registerHook(&SV_CreatePacketEntities, HC_PRIORITY_HIGH);
g_ReGameHookchains->CBasePlayer_Spawn()->registerHook(&CBasePlayer_Spawn, HC_PRIORITY_DEFAULT + 1);
g_ReGameHookchains->RadiusFlash_TraceLine()->registerHook(&RadiusFlash_TraceLine, HC_PRIORITY_HIGH);
if (g_Config.GetTime()) {
g_ReGameHookchains->CSGameRules_OnRoundFreezeEnd()->registerHook(&CSGameRules_OnRoundFreezeEnd, HC_PRIORITY_DEFAULT + 1);
}
if (g_Config.GetPenetFire()) {
g_ReGameHookchains->CBasePlayer_TraceAttack()->registerHook(&CBasePlayer_TraceAttack, HC_PRIORITY_DEFAULT + 1);
}
return TRUE;
}
void OnMetaDetach()
{
g_pFunctionTable->pfnPM_Move = nullptr;
g_pNewFunctionTable->pfnShouldCollide = nullptr;
g_RehldsHookchains->SV_CreatePacketEntities()->unregisterHook(&SV_CreatePacketEntities);
g_ReGameHookchains->InstallGameRules()->unregisterHook(&InstallGameRules);
g_ReGameHookchains->CBasePlayer_Spawn()->unregisterHook(&CBasePlayer_Spawn);
g_ReGameHookchains->RadiusFlash_TraceLine()->unregisterHook(&RadiusFlash_TraceLine);
if (g_Config.GetTime()) {
g_ReGameHookchains->CSGameRules_OnRoundFreezeEnd()->unregisterHook(&CSGameRules_OnRoundFreezeEnd);
}
if (g_Config.GetPenetFire()) {
g_ReGameHookchains->CBasePlayer_TraceAttack()->unregisterHook(&CBasePlayer_TraceAttack);
}
bActivated = false;
bInitialized = false;
}
void CGameData::Init()
{
SetStartEdict(INDEXENT(0));
}
inline void ClearAllClients()
{
for (int i = 0; i < g_GameData.GetMaxClients(); i++)
{
CGamePlayer *pPlayer = PLAYER_FOR_NUM(i);
if (!pPlayer) {
continue;
}
pPlayer->Player_Clear();
}
}
void ServerActivate_Post(edict_t *pEdictList, int edictCount, int clientMax)
{
bActivated = true;
g_GameData.SetMaxClients(clientMax);
g_GameData.SetMaxClientEdict(pEdictList + clientMax);
g_GameData.SetStartEnt(pEdictList + 1);
for (int i = 0; i < clientMax; i++)
{
CGamePlayer *pPlayer = PLAYER_FOR_NUM(i);
if (!pPlayer) {
continue;
}
pPlayer->Init(pEdictList, i);
}
for (auto& ent : g_RegVirtualTable)
{
edict_t *pEntity = CREATE_ENTITY();
CALL_GAME_ENTITY(PLID, ent.classname, VARS(pEntity));
if (pEntity->pvPrivateData) {
ent.ptr = *(CBaseEntity **)pEntity->pvPrivateData;
}
REMOVE_ENTITY(pEntity);
}
Load_Config_Maps();
SET_META_RESULT(MRES_IGNORED);
}
void ServerDeactivate_Post()
{
if (bInitialized)
{
if (bActivated)
{
ClearAllClients();
}
bInitialized = false;
bActivated = false;
}
SET_META_RESULT(MRES_IGNORED);
}
int DispatchSpawn(edict_t *pEntity)
{
if (!bInitialized)
{
g_GameData.Init();
bActivated = false;
bInitialized = true;
}
RETURN_META_VALUE(MRES_IGNORED, META_RESULT_ORIG_RET(int));
}
void CGamePlayer::Init(edict_t *pEdictList, int index)
{
this->m_iIndex = index + 1;
}
void CGamePlayer::Player_Clear()
{
m_bDont = false;
for (int i = 0; i <= g_GameData.GetMaxClients(); i++)
{
m_fDiff[i] = 0.0f;
m_bCrouch[i] = false;
m_bSolid[i] = false;
}
}
void ClientDisconnect(edict_t *pEdict)
{
if (bActivated)
{
CGamePlayer *pPlayer = PLAYER_FOR_EDICT(pEdict);
if (pPlayer != nullptr)
{
pPlayer->Player_Clear();
}
}
SET_META_RESULT(MRES_IGNORED);
}
int SV_CreatePacketEntities(IRehldsHook_SV_CreatePacketEntities *chain, sv_delta_t type, IGameClient *client, packet_entities_t *to, sizebuf_t *msg)
{
edict_t *pHost = client->GetEdict();
if (pHost->v.deadflag != DEAD_NO) {
return chain->callNext(type, client, to, msg);
}
CGamePlayer *pObject = nullptr;
CGamePlayer *pPlayer = PLAYER_FOR_EDICT(pHost);
CBasePlayer *pl = (CBasePlayer *)GET_PRIVATE(pHost);
for (int j = 0; j < to->num_entities; j++)
{
entity_state_t *state = to->entities + j;
int ent = state->number;
edict_t *pEnt = EDICT(ent);
if (ent <= g_GameData.GetMaxClients())
{
if (pEnt->v.deadflag != DEAD_NO || pEnt == pHost) {
continue;
}
pObject = PLAYER_FOR_EDICT(pEnt);
state_update:
if (pPlayer->GetSolid(pObject->GetIndex()))
{
state->solid = SOLID_NOT;
if (g_Config.GetTransparency())
{
state->rendermode = kRenderTransAlpha;
state->renderamt = g_Config.GetEffects() ? (pPlayer->GetDiff(pObject->GetIndex()) > MIN_AMOUNT) ? pPlayer->GetDiff(pObject->GetIndex()) : MIN_AMOUNT : g_Config.GetTransparency();
}
}
}
else
{
if (pl && pl->m_iTeam == TERRORIST)
{
CGrenade *pGrenade = (CGrenade *)GET_PRIVATE(pEnt);
if (*(CGrenade **)pGrenade == g_pVirtualGrenade && pGrenade->m_bIsC4)
{
state->solid = SOLID_NOT;
continue;
}
}
if (pEnt->v.aiment && pEnt->v.movetype == MOVETYPE_FOLLOW && pEnt->v.aiment != pHost)
{
int playerIndex = EDICT_NUM(pEnt->v.aiment);
if (playerIndex >= 1 && playerIndex <= g_GameData.GetMaxClients())
{
pObject = PLAYER_FOR_EDICT(pEnt->v.aiment);
goto state_update;
}
}
}
}
return chain->callNext(type, client, to, msg);
}
void CBasePlayer_Spawn(IReGameHook_CBasePlayer_Spawn *chain, CBasePlayer *pthis)
{
CGamePlayer *pPlayer = PLAYER_FOR_NUM(pthis->entindex() - 1);
if (pPlayer != nullptr)
{
pPlayer->Player_Clear();
}
chain->callNext(pthis);
}
inline bool IsTeamAllowed(CBasePlayer *HostPlayer, CBasePlayer *EntPlayer)
{
auto hostTeam = HostPlayer->m_iTeam;
if (hostTeam == SPECTATOR || g_Config.GetTeam() == SC_TEAM_ALL)
return true;
if (g_Config.GetTeam() == SC_TEAM_TEAMMATE)
return (CSGameRules()->PlayerRelationship(HostPlayer, EntPlayer) == GR_TEAMMATE);
// SC_TEAM_T, SC_TEAM_CT
return (hostTeam == g_Config.GetTeam() && EntPlayer->m_iTeam == g_Config.GetTeam());
}
inline bool allowDontSolid(playermove_t *pm, edict_t *pHost, int host, int j)
{
pHost = EDICT(host);
CBasePlayer *HostPlayer = (CBasePlayer *)CBaseEntity::Instance(pHost);
if (!HostPlayer || !HostPlayer->IsPlayer()) {
return false;
}
int ent = pm->physents[j].player;
edict_t *pEntity = EDICT(ent);
CBasePlayer *EntPlayer = (CBasePlayer *)CBaseEntity::Instance(pEntity);
if (!EntPlayer || !EntPlayer->IsPlayer()) {
return false;
}
CGamePlayer *pPlayer = PLAYER_FOR_NUM(host - 1);
CGamePlayer *pObject = PLAYER_FOR_NUM(ent - 1);
entvars_t *pevHost = &(pHost->v);
entvars_t *pevEnt = &(pEntity->v);
Vector hostOrigin = pevHost->origin;
Vector entOrigin = pevEnt->origin;
int IndexObject = pObject->GetIndex();
int hostTeamId = HostPlayer->m_iTeam;
int entTeamId = EntPlayer->m_iTeam;
*pPlayer->GetDiff(pObject) = GET_DISTANCE(hostOrigin, entOrigin);
*pPlayer->GetSolid(pObject) =
(
(g_Config.GetEffects() || *pPlayer->GetDiff(pObject) < g_Config.GetDistance()) && IsTeamAllowed(HostPlayer, EntPlayer) && !pObject->GetDont()
);
if (g_Config.GetCrouch() && pPlayer->GetSolid(IndexObject))
{
int IndexPlayer = pPlayer->GetIndex();
float fDiff = abs(hostOrigin.z - entOrigin.z);
if (fDiff < FLOAT_CROUCH
&& pPlayer->GetCrouch(IndexObject)
&& pObject->GetCrouch(IndexPlayer))
{
*pPlayer->GetCrouch(pObject) = false;
*pObject->GetCrouch(pPlayer) = false;
}
if (fDiff >= FLOAT_CROUCH
&& !pPlayer->GetCrouch(IndexObject)
&& pevHost->button & IN_DUCK
&& (pevEnt->button & IN_DUCK
|| pevEnt->flags & FL_DUCKING))
{
*pPlayer->GetCrouch(pObject) = true;
*pObject->GetCrouch(pPlayer) = true;
return *pPlayer->GetSolid(pObject) = false;
}
else if ((pPlayer->GetCrouch(IndexObject)
|| pObject->GetCrouch(IndexPlayer))
&& (pevHost->groundentity == pEntity
|| pevEnt->groundentity == pHost
|| fDiff >= FLOAT_CROUCH))
{
return *pPlayer->GetSolid(pObject) = false;
}
}
return pPlayer->GetSolid(IndexObject);
}
void PM_Move(playermove_t *pm, int server)
{
if (pm->deadflag != DEAD_NO || pm->dead || pm->spectator) {
RETURN_META(MRES_IGNORED);
}
int j, host, numphyspl = 0, numphysent = -1;
host = pm->player_index + 1;
edict_t *pHost = EDICT(host);
CBasePlayer *pCBasePlayer = (CBasePlayer *)CBaseEntity::Instance(pHost);
if (pCBasePlayer && pCBasePlayer->IsPlayer() && pCBasePlayer->m_iTeam == TERRORIST)
{
// to changes mins / maxs c4 from physents
for (int i = 0; i < pm->numphysent; ++i)
{
CBaseEntity *pEntity = (CBaseEntity *)GET_PRIVATE(EDICT(pm->physents[i].info));
CGrenade *pGrenade = (CGrenade *)pEntity;
if (*(CGrenade **)pGrenade != g_pVirtualGrenade || !pGrenade->m_bIsC4) {
continue;
}
pm->physents[i].maxs = {};
pm->physents[i].mins = {};
// it found
break;
}
}
for (j = 0; j < pm->numphysent; ++j)
{
if (pm->physents[++numphysent].player && ++numphyspl) {
break;
}
}
if (!numphyspl)
{
CGamePlayer *HostPlayer = PLAYER_FOR_NUM(host - 1);
if (HostPlayer != nullptr)
{
HostPlayer->Player_Clear();
}
}
for (j = numphysent; j < pm->numphysent; ++j)
{
if (!pm->physents[j].player || !allowDontSolid(pm, pHost, host, j))
{
pm->physents[numphysent++] = pm->physents[j];
}
}
if (g_Config.GetTime() && gpGlobals->time > g_Config.GetCount())
{
if (!pCBasePlayer || !pCBasePlayer->IsPlayer())
{
pm->numphysent = numphysent;
RETURN_META(MRES_IGNORED);
}
bool bCollide = false;
bool needSolid = false;
int hostTeamId = pCBasePlayer->m_iTeam;
Vector hostOrigin = pHost->v.origin;
CGamePlayer *pPlayer = PLAYER_FOR_NUM(host - 1);
edict_t *pEntity;
for (pEntity = g_GameData.GetStartEnt(), j = 1; pEntity <= g_GameData.GetMaxClientEdict(); pEntity++, j++)
{
if (!pEntity->pvPrivateData) {
continue;
}
CGamePlayer *pObject = PLAYER_FOR_NUM(j - 1);
if (pObject->GetDont()) {
continue;
}
entvars_t *e = &(pEntity->v);
if (e->deadflag != DEAD_NO || e->health <= 0.0) {
continue;
}
if (!bCollide && j != host && GET_COLLIDE(hostOrigin, e->origin))
{
CBasePlayer *EntPlayer = (CBasePlayer *)CBaseEntity::Instance(pEntity);
if (!EntPlayer || !EntPlayer->IsPlayer()) {
continue;
}
if (IsTeamAllowed(pCBasePlayer, EntPlayer))
{
bCollide = true;
}
}
needSolid = true;
if (bCollide && needSolid) {
break;
}
}
if (!numphyspl || !bCollide) {
pPlayer->SetDont(true);
}
if (!needSolid)
{
g_RehldsHookchains->SV_CreatePacketEntities()->unregisterHook(&SV_CreatePacketEntities);
g_ReGameHookchains->CBasePlayer_Spawn()->unregisterHook(&CBasePlayer_Spawn);
g_ReGameHookchains->CBasePlayer_TraceAttack()->unregisterHook(&CBasePlayer_TraceAttack);
g_pFunctionTable->pfnPM_Move = nullptr;
g_pNewFunctionTable->pfnShouldCollide = nullptr;
}
}
pm->numphysent = numphysent;
RETURN_META(MRES_IGNORED);
}
void RadiusFlash_TraceLine(IReGameHook_RadiusFlash_TraceLine *chain, CBasePlayer *pPlayer, entvars_t *pevInflictor, entvars_t *pevAttacker, Vector& vecSrc, Vector& vecSpot, TraceResult *ptr)
{
chain->callNext(pPlayer, pevInflictor, pevAttacker, vecSrc, vecSpot, ptr);
CGamePlayer *pHost = PLAYER_FOR_EDICT(pPlayer->edict());
for (int i = 0; i < g_GameData.GetMaxClients(); i++)
{
edict_t *pHit = ptr->pHit;
if (pHit < g_GameData.GetStartEnt() || pHit > g_GameData.GetMaxClientEdict()) {
break;
}
CGamePlayer *pTarget = PLAYER_FOR_EDICT(pHit);
if (!pHost->GetSolid(pTarget->GetIndex())) {
break;
}
vecSrc = pHit->v.origin + pHit->v.view_ofs;
TRACE_LINE(vecSrc, vecSpot, 0, pHit, ptr);
}
}
void CSGameRules_OnRoundFreezeEnd(IReGameHook_CSGameRules_OnRoundFreezeEnd *chain)
{
chain->callNext();
ClearAllClients();
g_Config.SetCount(gpGlobals->time + g_Config.GetTime());
g_RehldsHookchains->SV_CreatePacketEntities()->unregisterHook(&SV_CreatePacketEntities);
g_RehldsHookchains->SV_CreatePacketEntities()->registerHook(&SV_CreatePacketEntities, HC_PRIORITY_HIGH);
g_ReGameHookchains->CBasePlayer_Spawn()->unregisterHook(&CBasePlayer_Spawn);
g_ReGameHookchains->CBasePlayer_Spawn()->registerHook(&CBasePlayer_Spawn, HC_PRIORITY_DEFAULT + 1);
g_ReGameHookchains->CBasePlayer_TraceAttack()->unregisterHook(&CBasePlayer_TraceAttack);
g_ReGameHookchains->CBasePlayer_TraceAttack()->registerHook(&CBasePlayer_TraceAttack, HC_PRIORITY_DEFAULT + 1);
g_pFunctionTable->pfnPM_Move = PM_Move;
g_pNewFunctionTable->pfnShouldCollide = ShouldCollide;
}
void SVR_SemiclipOption()
{
if (CMD_ARGC() < 3)
{
Print_Settings();
return;
}
const char *argv = CMD_ARGV(1);
const char *value = CMD_ARGV(2);
if (*value == '\0') {
return;
}
if (!g_Config.Parse_Settings(argv, value)) {
Print_Settings();
}
else if (!g_Config.GetEnable())
{
g_RehldsHookchains->SV_CreatePacketEntities()->unregisterHook(&SV_CreatePacketEntities);
g_ReGameHookchains->CBasePlayer_Spawn()->unregisterHook(&CBasePlayer_Spawn);
g_ReGameHookchains->CBasePlayer_TraceAttack()->unregisterHook(&CBasePlayer_TraceAttack);
g_ReGameHookchains->CSGameRules_OnRoundFreezeEnd()->unregisterHook(&CSGameRules_OnRoundFreezeEnd);
g_pFunctionTable->pfnPM_Move = nullptr;
g_pNewFunctionTable->pfnShouldCollide = nullptr;
}
else
{
if (!strcasecmp(argv, "time"))
{
if (g_Config.GetTime()) {
g_ReGameHookchains->CSGameRules_OnRoundFreezeEnd()->registerHook(&CSGameRules_OnRoundFreezeEnd, HC_PRIORITY_DEFAULT + 1);
}
else
{
ClearAllClients();
g_RehldsHookchains->SV_CreatePacketEntities()->unregisterHook(&SV_CreatePacketEntities);
g_RehldsHookchains->SV_CreatePacketEntities()->registerHook(&SV_CreatePacketEntities, HC_PRIORITY_HIGH);
g_ReGameHookchains->CBasePlayer_Spawn()->unregisterHook(&CBasePlayer_Spawn);
g_ReGameHookchains->CBasePlayer_Spawn()->registerHook(&CBasePlayer_Spawn, HC_PRIORITY_DEFAULT + 1);
g_ReGameHookchains->CSGameRules_OnRoundFreezeEnd()->unregisterHook(&CSGameRules_OnRoundFreezeEnd);
g_pFunctionTable->pfnPM_Move = PM_Move;
g_pNewFunctionTable->pfnShouldCollide = ShouldCollide;
}
}
else if (!strcasecmp(argv, "penetfire"))
{
if (g_Config.GetPenetFire()) {
g_ReGameHookchains->CBasePlayer_TraceAttack()->unregisterHook(&CBasePlayer_TraceAttack);
g_ReGameHookchains->CBasePlayer_TraceAttack()->registerHook(&CBasePlayer_TraceAttack, HC_PRIORITY_DEFAULT + 1);
}
else
{
g_ReGameHookchains->CBasePlayer_TraceAttack()->unregisterHook(&CBasePlayer_TraceAttack);
}
}
}
}
class CGroupMask
{
public:
CGroupMask(CBasePlayer *pAttacker)
{
m_pev = pAttacker->pev;
m_iTeam = pAttacker->m_iTeam;
m_iIndex = pAttacker->entindex();
m_pAttacker = PLAYER_FOR_EDICT(pAttacker->edict());
}
void SetGroupMask()
{
for (int i = 1; i <= g_GameData.GetMaxClients(); ++i)
{
CBasePlayer *pPlayer = UTIL_PlayerByIndex(i);
if (!pPlayer || pPlayer->m_iTeam != m_iTeam || i == m_iIndex) {
continue;
}
CGamePlayer *pGamePlayer = PLAYER_FOR_EDICT(pPlayer->edict());
if (pGamePlayer && pGamePlayer->GetSolid(m_iIndex))
{
pPlayer->pev->groupinfo |= (1 << m_iIndex) | (1 << i);
}
if (m_pAttacker->GetSolid(i))
{
m_pev->groupinfo |= (1 << m_iIndex) | (1 << i);
}
}
ENGINE_SETGROUPMASK(0, GROUP_OP_NAND);
}
void ResetGroupMask()
{
for (int i = 1; i <= g_GameData.GetMaxClients(); ++i)
{
CBasePlayer *pPlayer = UTIL_PlayerByIndex(i);
if (!pPlayer || pPlayer->m_iTeam != m_iTeam || i == m_iIndex) {
continue;
}
pPlayer->pev->groupinfo &= ~((1 << i) | (1 << m_iIndex));
m_pev->groupinfo &= ~((1 << i) | (1 << m_iIndex));
}
ENGINE_SETGROUPMASK(0, GROUP_OP_AND);
}
private:
CGamePlayer *m_pAttacker;
entvars_t *m_pev;
int m_iTeam;
int m_iIndex;
};
void CBasePlayer_TraceAttack(IReGameHook_CBasePlayer_TraceAttack *chain, CBasePlayer *pthis, entvars_t *pevAttacker, float flDamage, Vector& vecDir, TraceResult *ptr, int bitsDamageType)
{
CBasePlayer *pAttacker((CBasePlayer *)CBaseEntity::Instance(pevAttacker));
if (CSGameRules()->FPlayerCanTakeDamage(pthis, pAttacker)) {
chain->callNext(pthis, pevAttacker, flDamage, vecDir, ptr, bitsDamageType);
return;
}
const float flForward = (pAttacker->m_pActiveItem && pAttacker->m_pActiveItem->m_iId == WEAPON_KNIFE) ? 48.0f : 8192.0f;
TraceResult tr;
Vector vecStart(pAttacker->pev->origin + pAttacker->pev->view_ofs);
Vector vecEnd(vecStart + vecDir * flForward);
CGroupMask mask(pAttacker);
mask.SetGroupMask();
UTIL_TraceLine(vecStart, vecEnd, dont_ignore_monsters, pAttacker->edict(), &tr);
mask.ResetGroupMask();
if (tr.flFraction == 1.0f) {
return;
}
CBasePlayer *pHit = (CBasePlayer *)CBaseEntity::Instance(tr.pHit);
if (pHit != nullptr)
{
if (pHit->IsPlayer()) {
chain->callNext(pHit, pevAttacker, flDamage, vecDir, &tr, bitsDamageType);
}
else
{
chain->callNext(pthis, pevAttacker, flDamage, vecDir, ptr, bitsDamageType);
}
}
}
int ShouldCollide(edict_t *pentTouched, edict_t *pentOther)
{
CBaseEntity *pTouched = (CBaseEntity *)GET_PRIVATE(pentTouched);
CBaseEntity *pOther = (CBaseEntity *)GET_PRIVATE(pentOther);
if (pOther && pTouched && pTouched->IsPlayer())
{
// ignore owner's
if (pentTouched->v.owner == pentOther || pentOther->v.owner == pentTouched) {
RETURN_META_VALUE(MRES_IGNORED, 0);
}
if (!((pTouched->pev->flags | pOther->pev->flags) & FL_KILLME))
{
// if collided grenade / c4
CGrenade *pGrenadeOther = (CGrenade *)pOther;
if (*(CGrenade **)pGrenadeOther == g_pVirtualGrenade && pGrenadeOther->pev->owner)
{
if (pGrenadeOther->m_bIsC4 && ((CBasePlayer *)pTouched)->m_iTeam == TERRORIST) {
RETURN_META_VALUE(MRES_SUPERCEDE, 0);
}
CGamePlayer *pGamePlayer = PLAYER_FOR_EDICT(pGrenadeOther->pev->owner);
if (pGamePlayer && pGamePlayer->GetSolid(EDICT_NUM(pentTouched))) {
RETURN_META_VALUE(MRES_SUPERCEDE, 0);
}
}
}
}
RETURN_META_VALUE(MRES_IGNORED, 0);
}