diff --git a/rehlds/engine/sv_user.cpp b/rehlds/engine/sv_user.cpp index e122bde..18bb80f 100644 --- a/rehlds/engine/sv_user.cpp +++ b/rehlds/engine/sv_user.cpp @@ -33,42 +33,6 @@ qboolean g_balreadymoved; float s_LastFullUpdate[33]; -//cvar_t sv_voicecodec; -//cvar_t sv_voicequality;/* -* -* This program is free software; you can redistribute it and/or modify it -* under the terms of the GNU General Public License as published by the -* Free Software Foundation; either version 2 of the License, or (at -* your option) any later version. -* -* This program is distributed in the hope that it will be useful, but -* WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software Foundation, -* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -* -* In addition, as a special exception, the author gives permission to -* link the code of this program with the Half-Life Game Engine ("HL -* Engine") and Modified Game Libraries ("MODs") developed by Valve, -* L.L.C ("Valve"). You must obey the GNU General Public License in all -* respects for all of the code used other than the HL Engine and MODs -* from Valve. If you modify this file, you may extend this exception -* to your version of the file, but you are not obligated to do so. If -* you do not wish to do so, delete this exception statement from your -* version. -* -*/ - -#include "precompiled.h" - -sv_adjusted_positions_t truepositions[MAX_CLIENTS]; -qboolean g_balreadymoved; - -float s_LastFullUpdate[33]; - //cvar_t sv_voicecodec; //cvar_t sv_voicequality; @@ -1621,7 +1585,7 @@ void SV_ParseMove(client_t *pSenderClient) return; } } - + COM_UnMunge(&net_message.data[placeholder + 1], mlen, host_client->netchan.incoming_sequence); packetLossByte = MSG_ReadByte(); @@ -1833,7 +1797,7 @@ void EXT_FUNC SV_HandleClientMessage_api(IGameClient* client, uint8 opcode) { { Con_Printf("SV_ReadClientMessage: unknown command char (%d)\n", opcode); } - + SV_DropClient(cl, FALSE, "Bad command character in client command"); return; } @@ -1887,7 +1851,7 @@ void SV_ExecuteClientMessage(client_t *cl) { Con_Printf("SV_ReadClientMessage: badread on %s\n", host_client->name); } - + if (host_client->active) SV_ClientPrintf("Badread\n"); #else // REHLDS_FIXES @@ -2036,1948 +2000,3 @@ void SV_FullUpdate_f(void) gEntityInterface.pfnClientCommand(sv_player); #endif // REHLDS_FIXES } - -edict_t *sv_player; - -//int giSkip; -qboolean nofind; - -#if defined(SWDS) && defined(REHLDS_FIXES) -const char *clcommands[] = { "status", "name", "kill", "pause", "spawn", "new", "sendres", "dropclient", "kick", "ping", "dlfile", "setinfo", "sendents", "fullupdate", "setpause", "unpause", NULL }; -#else -const char *clcommands[23] = { "status", "god", "notarget", "fly", "name", "noclip", "kill", "pause", "spawn", "new", "sendres", "dropclient", "kick", "ping", "dlfile", "nextdl", "setinfo", "showinfo", "sendents", "fullupdate", "setpause", "unpause", NULL }; -#endif - -cvar_t sv_edgefriction = { "edgefriction", "2", FCVAR_SERVER, 0.0f, NULL }; -cvar_t sv_maxspeed = { "sv_maxspeed", "320", FCVAR_SERVER, 0.0f, NULL }; -cvar_t sv_accelerate = { "sv_accelerate", "10", FCVAR_SERVER, 0.0f, NULL }; -cvar_t sv_footsteps = { "mp_footsteps", "1", FCVAR_SERVER, 0.0f, NULL }; -cvar_t sv_rollspeed = { "sv_rollspeed", "0.0", 0, 0.0f, NULL }; -cvar_t sv_rollangle = { "sv_rollangle", "0.0", 0, 0.0f, NULL }; -cvar_t sv_unlag = { "sv_unlag", "1", 0, 0.0f, NULL }; -cvar_t sv_maxunlag = { "sv_maxunlag", "0.5", 0, 0.0f, NULL }; -cvar_t sv_unlagpush = { "sv_unlagpush", "0.0", 0, 0.0f, NULL }; -cvar_t sv_unlagsamples = { "sv_unlagsamples", "1", 0, 0.0f, NULL }; -cvar_t mp_consistency = { "mp_consistency", "1", FCVAR_SERVER, 0.0f, NULL }; -cvar_t sv_voiceenable = { "sv_voiceenable", "1", FCVAR_SERVER | FCVAR_ARCHIVE, 0.0f, NULL }; - -clc_func_t sv_clcfuncs[] = { - { clc_bad, "clc_bad", nullptr }, - { clc_nop, "clc_nop", nullptr }, - { clc_move, "clc_move", &SV_ParseMove }, - { clc_stringcmd, "clc_stringcmd", &SV_ParseStringCommand }, - { clc_delta, "clc_delta", &SV_ParseDelta }, - { clc_resourcelist, "clc_resourcelist", &SV_ParseResourceList }, - { clc_tmove, "clc_tmove", nullptr }, - { clc_fileconsistency, "clc_fileconsistency", &SV_ParseConsistencyResponse }, - { clc_voicedata, "clc_voicedata", &SV_ParseVoiceData }, - { clc_hltv, "clc_hltv", &SV_IgnoreHLTV }, - { clc_cvarvalue, "clc_cvarvalue", &SV_ParseCvarValue }, - { clc_cvarvalue2, "clc_cvarvalue2", &SV_ParseCvarValue2 }, - { clc_endoflist, "End of List", nullptr }, -}; - -bool EXT_FUNC SV_CheckConsistencyResponse_API(IGameClient *client, resource_t *res, uint32 hash) { - return (hash != *(uint32 *)&res->rgucMD5_hash[0]); -} - -void SV_ParseConsistencyResponse(client_t *pSenderClient) -{ - vec3_t mins; - vec3_t maxs; - vec3_t cmins; - vec3_t cmaxs; - unsigned char nullbuffer[32]; - unsigned char resbuffer[32]; - - int length = 0; - int c = 0; - Q_memset(nullbuffer, 0, sizeof(nullbuffer)); - int value = MSG_ReadShort(); - - if (value <= 0 || !SZ_HasSomethingToRead(&net_message, value)) - { - msg_badread = TRUE; - Con_DPrintf("%s: %s:%s invalid length: %d\n", __func__, host_client->name, NET_AdrToString(host_client->netchan.remote_address), value); - SV_DropClient(host_client, FALSE, "Invalid length"); - return; - } - - COM_UnMunge(&net_message.data[msg_readcount], value, g_psvs.spawncount); - MSG_StartBitReading(&net_message); - - while (MSG_ReadBits(1)) - { - int idx = MSG_ReadBits(12); - if (idx < 0 || idx >= g_psv.num_resources) - { - c = -1; - break; - } - -#ifdef REHLDS_FIXES - resource_t *r = &g_rehlds_sv.resources[idx]; -#else // REHLDS_FIXES - resource_t *r = &g_psv.resourcelist[idx]; -#endif // REHLDS_FIXES - if (!(r->ucFlags & RES_CHECKFILE)) - { - c = -1; - break; - } - - Q_memcpy(resbuffer, r->rguc_reserved, sizeof(resbuffer)); - if (!Q_memcmp(resbuffer, nullbuffer, sizeof(resbuffer))) - { - uint32 hash = MSG_ReadBits(32); - if (g_RehldsHookchains.m_SV_CheckConsistencyResponse.callChain(SV_CheckConsistencyResponse_API, GetRehldsApiClient(pSenderClient), r, hash)) - c = idx + 1; - } - else - { - MSG_ReadBitData(cmins, 12); - MSG_ReadBitData(cmaxs, 12); - Q_memcpy(resbuffer, r->rguc_reserved, sizeof(resbuffer)); - COM_UnMunge(resbuffer, sizeof(resbuffer), g_psvs.spawncount); - FORCE_TYPE ft = (FORCE_TYPE)resbuffer[0]; - if (ft == force_model_samebounds) - { - Q_memcpy(mins, &resbuffer[1], 12); - Q_memcpy(maxs, &resbuffer[13], 12); - if (!VectorCompare(cmins, mins) || !VectorCompare(cmaxs, maxs)) - c = idx + 1; - } - else if (ft == force_model_specifybounds) - { - Q_memcpy(mins, &resbuffer[1], 12); - Q_memcpy(maxs, &resbuffer[13], 12); - for (int i = 0; i < 3; i++) - { - if (cmins[i] < mins[i] || cmaxs[i] > maxs[i]) - { - c = idx + 1; - break; - } - } - } - else if (ft == force_model_specifybounds_if_avail) - { - Q_memcpy(mins, &resbuffer[1], 12); - Q_memcpy(maxs, &resbuffer[13], 12); - if (cmins[0] != -1.0 || cmins[1] != -1.0 || cmins[2] != -1.0 || cmaxs[0] != -1.0 || cmaxs[1] != -1.0 || cmaxs[2] != -1.0) - { - for (int i = 0; i < 3; i++) - { - if (cmins[i] < mins[i] || cmaxs[i] > maxs[i]) - { - c = idx + 1; - break; - } - } - } - } - else - { - msg_badread = 1; - c = idx + 1; - break; - } - - } - - if (msg_badread) - break; - - ++length; - } - - MSG_EndBitReading(&net_message); - if (c < 0 || length != g_psv.num_consistency) - { - msg_badread = 1; - Con_Printf("SV_ParseConsistencyResponse: %s:%s sent bad file data\n", host_client->name, NET_AdrToString(host_client->netchan.remote_address)); - SV_DropClient(host_client, FALSE, "Bad file data"); - return; - } - - if (c > 0) - { - char dropmessage[256]; -#ifdef REHLDS_FIXES - dropmessage[0] = '\0'; - - if (gEntityInterface.pfnInconsistentFile(host_client->edict, g_rehlds_sv.resources[c - 1].szFileName, dropmessage)) - { - if (dropmessage[0]) - SV_ClientPrintf("%s", dropmessage); - - SV_DropClient(host_client, FALSE, "Bad file %s", g_rehlds_sv.resources[c - 1].szFileName); // only filename. reason was printed in console if exists. - return; - } -#else // REHLDS_FIXES - if (gEntityInterface.pfnInconsistentFile(host_client->edict, g_psv.resourcelist[c - 1].szFileName, dropmessage)) - { - if (Q_strlen(dropmessage) > 0) - SV_ClientPrintf("%s", dropmessage); - - SV_DropClient(host_client, FALSE, "Bad file %s", dropmessage); - } - return; -#endif // REHLDS_FIXES - } - - // Reset has_force_unmodified if we have received response from the client - host_client->has_force_unmodified = FALSE; -} - -qboolean EXT_FUNC SV_FileInConsistencyList(const char *filename, consistency_t **ppconsist) -{ - for (int i = 0; i < ARRAYSIZE(g_psv.consistency_list); i++) - { - if (!g_psv.consistency_list[i].filename) - return 0; - - if (!Q_stricmp(filename, g_psv.consistency_list[i].filename)) - { - if (ppconsist) - *ppconsist = &g_psv.consistency_list[i]; - return 1; - } - } - - return 0; -} - -int SV_TransferConsistencyInfo(void) -{ - return g_RehldsHookchains.m_SV_TransferConsistencyInfo.callChain(SV_TransferConsistencyInfo_internal); -} - -int EXT_FUNC SV_TransferConsistencyInfo_internal(void) -{ - consistency_t *pc; - - int c = 0; - for (int i = 0; i < g_psv.num_resources; i++) - { -#ifdef REHLDS_FIXES - resource_t *r = &g_rehlds_sv.resources[i]; -#else // REHLDS_FIXES - resource_t *r = &g_psv.resourcelist[i]; -#endif // REHLDS_FIXES - if (r->ucFlags == (RES_CUSTOM | RES_REQUESTED | RES_UNK_6) || (r->ucFlags & RES_CHECKFILE)) - continue; - - if (!SV_FileInConsistencyList(r->szFileName, &pc)) - continue; - - r->ucFlags |= RES_CHECKFILE; - - char filename[MAX_PATH]; - if (r->type != t_sound) - { - Q_strncpy(filename, r->szFileName, MAX_PATH - 1); - filename[MAX_PATH - 1] = 0; - } - else - { - Q_snprintf(filename, MAX_PATH, "sound/%s", r->szFileName); - } - MD5_Hash_File(r->rgucMD5_hash, filename, FALSE, FALSE, NULL); - - if (r->type == t_model) - { - if (pc->check_type == force_model_samebounds) - { - vec3_t mins; - vec3_t maxs; - - if (!R_GetStudioBounds(filename, mins, maxs)) - Host_Error("%s: Server unable to get bounds for %s\n", __func__, filename); - - Q_memcpy(&r->rguc_reserved[1], mins, sizeof(mins)); - Q_memcpy(&r->rguc_reserved[13], maxs, sizeof(maxs)); - } - else if (pc->check_type == force_model_specifybounds || pc->check_type == force_model_specifybounds_if_avail) - { - Q_memcpy(&r->rguc_reserved[1], pc->mins, sizeof(pc->mins)); - Q_memcpy(&r->rguc_reserved[13], pc->maxs, sizeof(pc->maxs)); - } - else - { - ++c; - continue; - } - r->rguc_reserved[0] = pc->check_type; - COM_Munge(r->rguc_reserved, 32, g_psvs.spawncount); - } - ++c; - } - return c; -} - -bool EXT_FUNC SV_ShouldSendConsistencyList_mod(IGameClient *cl, bool forceConsistency) -{ - if (g_psvs.maxclients == 1 || g_psv.num_consistency == 0 || cl->IsProxy()) - return false; - - if (!forceConsistency && mp_consistency.value == 0.0f) - return false; - - return true; -} - -bool SV_ShouldSendConsistencyList(client_t *client, bool forceConsistency) -{ - return g_RehldsHookchains.m_SV_ShouldSendConsistencyList.callChain(SV_ShouldSendConsistencyList_mod, GetRehldsApiClient(client), forceConsistency); -} - -void SV_SendConsistencyList(sizebuf_t *msg) -{ - host_client->has_force_unmodified = FALSE; - - if (!SV_ShouldSendConsistencyList(host_client, false)) - { - MSG_WriteBits(0, 1); - return; - } - - host_client->has_force_unmodified = TRUE; - - int delta = 0; - int lastcheck = 0; -#ifdef REHLDS_FIXES - resource_t *r = g_rehlds_sv.resources; -#else // REHLDS_FIXES - resource_t *r = g_psv.resourcelist; -#endif // REHLDS_FIXES - - MSG_WriteBits(1, 1); - - for (int i = 0; i < g_psv.num_resources; i++, r++) - { - if (r && (r->ucFlags & RES_CHECKFILE) != 0) - { - MSG_WriteBits(1, 1); - delta = i - lastcheck; - - if (delta > 31) - { - MSG_WriteBits(0, 1); - MSG_WriteBits(i, 10); // LIMIT: Here it write index, not a diff, with resolution of 10 bits. So, it limits not adjacent index to 1023 max. - } - else - { - // Write 5 bits index delta, so it is up to 31 - MSG_WriteBits(1, 1); - MSG_WriteBits(delta, 5); - } - - lastcheck = i; - } - } - - MSG_WriteBits(0, 1); -} - -void SV_PreRunCmd(void) -{ -} - -void SV_CopyEdictToPhysent(physent_t *pe, int e, edict_t *check) -{ - model_t *pModel; - - pe->origin[0] = check->v.origin[0]; - pe->origin[1] = check->v.origin[1]; - pe->origin[2] = check->v.origin[2]; - - pe->info = e; - - if (e < 1 || e > g_psvs.maxclients) - { - pe->player = 0; - } - else - { - SV_GetTrueOrigin(e - 1, pe->origin); - pe->player = pe->info; - } - - pe->angles[0] = check->v.angles[0]; - pe->angles[1] = check->v.angles[1]; - pe->angles[2] = check->v.angles[2]; - - pe->studiomodel = nullptr; - pe->rendermode = check->v.rendermode; - - if (check->v.solid == SOLID_BSP) - { - pe->model = g_psv.models[check->v.modelindex]; - Q_strncpy(pe->name, pe->model->name, sizeof(pe->name) - 1); - pe->name[sizeof(pe->name) - 1] = 0; - } - else if (check->v.solid == SOLID_NOT) - { - if (check->v.modelindex) - { - pe->model = g_psv.models[check->v.modelindex]; - Q_strncpy(pe->name, pe->model->name, sizeof(pe->name) - 1); - pe->name[sizeof(pe->name) - 1] = 0; - } - else - { - pe->model = nullptr; - } - } - else - { - pe->model = nullptr; - if (check->v.solid != SOLID_BBOX) - { - pe->mins[0] = check->v.mins[0]; - pe->mins[1] = check->v.mins[1]; - pe->maxs[0] = check->v.maxs[0]; - pe->mins[2] = check->v.mins[2]; - pe->maxs[1] = check->v.maxs[1]; - pe->maxs[2] = check->v.maxs[2]; - - if (check->v.classname) - { - Q_strncpy(pe->name, &pr_strings[check->v.classname], sizeof(pe->name) - 1); - pe->name[sizeof(pe->name) - 1] = 0; - } - else - { - Q_sprintf(pe->name, "?"); - } - } - else - { - if (check->v.modelindex) - { - pModel = g_psv.models[check->v.modelindex]; - if (pModel) - { - if (pModel->flags & STUDIO_TRACE_HITBOX) - pe->studiomodel = pModel; - - Q_strncpy(pe->name, pModel->name, sizeof(pe->name) - 1); - pe->name[sizeof(pe->name) - 1] = 0; - } - } - - pe->mins[0] = check->v.mins[0]; - pe->mins[1] = check->v.mins[1]; - pe->mins[2] = check->v.mins[2]; - pe->maxs[0] = check->v.maxs[0]; - pe->maxs[1] = check->v.maxs[1]; - pe->maxs[2] = check->v.maxs[2]; - } - } - - pe->skin = check->v.skin; - pe->frame = check->v.frame; - pe->solid = check->v.solid; - pe->sequence = check->v.sequence; - pe->movetype = check->v.movetype; - - Q_memcpy(&pe->controller[0], &check->v.controller[0], 4 * sizeof(byte)); - Q_memcpy(&pe->blending[0], &check->v.blending[0], 2 * sizeof(byte)); - - pe->iuser1 = check->v.iuser1; - pe->iuser2 = check->v.iuser2; - pe->iuser3 = check->v.iuser3; - pe->iuser4 = check->v.iuser4; - pe->fuser1 = check->v.fuser1; - pe->fuser2 = check->v.fuser2; - pe->fuser3 = check->v.fuser3; - pe->fuser4 = check->v.fuser4; - - pe->vuser1[0] = check->v.vuser1[0]; - pe->vuser1[1] = check->v.vuser1[1]; - pe->vuser1[2] = check->v.vuser1[2]; - pe->vuser2[0] = check->v.vuser2[0]; - pe->vuser2[1] = check->v.vuser2[1]; - pe->vuser2[2] = check->v.vuser2[2]; - pe->vuser3[0] = check->v.vuser3[0]; - pe->vuser3[1] = check->v.vuser3[1]; - pe->vuser3[2] = check->v.vuser3[2]; - - pe->takedamage = 0; - pe->blooddecal = 0; - - pe->vuser4[0] = check->v.vuser4[0]; - pe->vuser4[1] = check->v.vuser4[1]; - pe->vuser4[2] = check->v.vuser4[2]; -} - -void SV_AddLinksToPM_(areanode_t *node, float *pmove_mins, float *pmove_maxs) -{ - struct link_s *l; - edict_t *check; - int e; - physent_t *ve; - int i; - link_t *next; - float *fmax; - float *fmin; - physent_t *pe; - - for (l = node->solid_edicts.next; l != &node->solid_edicts; l = next) - { - check = (edict_t *)&l[-1]; - next = l->next; - if (check->v.groupinfo) - { - if (g_groupop) - { - if (g_groupop == GROUP_OP_NAND && (check->v.groupinfo & sv_player->v.groupinfo)) - continue; - } - else - { - if (!(check->v.groupinfo & sv_player->v.groupinfo)) - continue; - } - } - - if (check->v.owner == sv_player) - continue; - - if (check->v.solid != SOLID_BSP && check->v.solid != SOLID_BBOX && check->v.solid != SOLID_SLIDEBOX && check->v.solid != SOLID_NOT) - continue; - - e = NUM_FOR_EDICT(check); - ve = &pmove->visents[pmove->numvisent]; - pmove->numvisent = pmove->numvisent + 1; - SV_CopyEdictToPhysent(ve, e, check); - - if ((check->v.solid == SOLID_NOT) && (!check->v.skin || !check->v.modelindex)) - continue; - - if ((check->v.flags & FL_MONSTERCLIP) && check->v.solid == SOLID_BSP) - continue; - - if (check == sv_player) - continue; - - if ((check->v.flags & FL_CLIENT) && check->v.health <= 0.0) - continue; - - if (check->v.mins[2] == 0.0 && check->v.maxs[2] == 1.0) - continue; - - if (Length(check->v.size) == 0.0) - continue; - - fmin = check->v.absmin; - fmax = check->v.absmax; - if (check->v.flags & FL_CLIENT) - SV_GetTrueMinMax(e - 1, &fmin, &fmax); - - for (i = 0; i < 3; i++) - { - if (fmin[i] > pmove_maxs[i] || fmax[i] < pmove_mins[i]) - break; - } - - if (i != 3) - continue; - - if (check->v.solid || check->v.skin != -16) - { - if (pmove->numphysent >= MAX_PHYSENTS) - { - Con_DPrintf("SV_AddLinksToPM: pmove->numphysent >= MAX_PHYSENTS\n"); - return; - } - pe = &pmove->physents[pmove->numphysent++]; - } - else - { - if (pmove->nummoveent >= MAX_MOVEENTS) - { - Con_DPrintf("SV_AddLinksToPM: pmove->nummoveent >= MAX_MOVEENTS\n"); - continue; - } - pe = &pmove->moveents[pmove->nummoveent++]; - } - - Q_memcpy(pe, ve, sizeof(physent_t)); - } - - if (node->axis != -1) - { - if (pmove_maxs[node->axis] > node->dist) - SV_AddLinksToPM_(node->children[0], pmove_mins, pmove_maxs); - - if (pmove_mins[node->axis] < node->dist) - SV_AddLinksToPM_(node->children[1], pmove_mins, pmove_maxs); - } -} - -void SV_AddLinksToPM(areanode_t *node, vec_t *origin) -{ - vec3_t pmove_mins; - vec3_t pmove_maxs; - - Q_memset(&pmove->physents[0], 0, sizeof(physent_t)); - Q_memset(&pmove->visents[0], 0, sizeof(physent_t)); - - pmove->physents[0].model = g_psv.worldmodel; - if (g_psv.worldmodel != NULL) - { - Q_strncpy(pmove->physents[0].name, g_psv.worldmodel->name, sizeof(pmove->physents[0].name) - 1); - pmove->physents[0].name[sizeof(pmove->physents[0].name) - 1] = 0; - } - pmove->physents[0].origin[0] = vec3_origin[0]; - pmove->physents[0].origin[1] = vec3_origin[1]; - pmove->physents[0].origin[2] = vec3_origin[2]; - pmove->physents[0].info = 0; - pmove->physents[0].solid = 4; - pmove->physents[0].movetype = 0; - pmove->physents[0].takedamage = 1; - pmove->physents[0].blooddecal = 0; - pmove->numphysent = 1; - pmove->numvisent = 1; - pmove->visents[0] = pmove->physents[0]; - pmove->nummoveent = 0; - for (int i = 0; i < 3; i++) - { - pmove_mins[i] = origin[i] - 256.0f; - pmove_maxs[i] = origin[i] + 256.0f; - } - SV_AddLinksToPM_(node, pmove_mins, pmove_maxs); -} - -void SV_PlayerRunPreThink(edict_t *player, float time) -{ - gGlobalVariables.time = time; - gEntityInterface.pfnPlayerPreThink(player); -} - -qboolean SV_PlayerRunThink(edict_t *ent, float frametime, double clienttimebase) -{ - float thinktime; - - if (!(ent->v.flags & (FL_DORMANT | FL_KILLME))) - { - thinktime = ent->v.nextthink; - if (thinktime <= 0.0 || frametime + clienttimebase < thinktime) - return 1; - - if (thinktime < clienttimebase) - thinktime = (float)clienttimebase; - - ent->v.nextthink = 0; - gGlobalVariables.time = thinktime; - gEntityInterface.pfnThink(ent); - } - - if (ent->v.flags & FL_KILLME) - ED_Free(ent); - - return ent->free == 0; -} - -void SV_CheckMovingGround(edict_t *player, float frametime) -{ - edict_t *groundentity; - - if (player->v.flags & FL_ONGROUND) - { - groundentity = player->v.groundentity; - if (groundentity) - { - if (groundentity->v.flags & FL_CONVEYOR) - { - if (player->v.flags & FL_BASEVELOCITY) - VectorMA(player->v.basevelocity, groundentity->v.speed, groundentity->v.movedir, player->v.basevelocity); - else - VectorScale(groundentity->v.movedir, groundentity->v.speed, player->v.basevelocity); - player->v.flags |= FL_BASEVELOCITY; - } - } - } - - if (!(player->v.flags & FL_BASEVELOCITY)) - { - VectorMA(player->v.velocity, frametime * 0.5f + 1.0f, player->v.basevelocity, player->v.velocity); - player->v.basevelocity[0] = 0; - player->v.basevelocity[1] = 0; - player->v.basevelocity[2] = 0; - } - - player->v.flags &= ~FL_BASEVELOCITY; -} - -void SV_ConvertPMTrace(trace_t *dest, pmtrace_t *src, edict_t *ent) -{ - dest->allsolid = src->allsolid; - dest->startsolid = src->startsolid; - dest->inopen = src->inopen; - dest->inwater = src->inwater; - dest->fraction = src->fraction; - dest->endpos[0] = src->endpos[0]; - dest->endpos[1] = src->endpos[1]; - dest->endpos[2] = src->endpos[2]; - dest->plane.normal[0] = src->plane.normal[0]; - dest->plane.normal[1] = src->plane.normal[1]; - dest->plane.normal[2] = src->plane.normal[2]; - dest->plane.dist = src->plane.dist; - dest->hitgroup = src->hitgroup; - dest->ent = ent; -} - -void SV_ForceFullClientsUpdate(void) -{ - byte data[9216]; - sizebuf_t msg; - - Q_memset(&msg, 0, sizeof(msg)); - msg.buffername = "Force Update"; - msg.data = data; - msg.cursize = 0; - msg.maxsize = sizeof(data); - - for (int i = 0; i < g_psvs.maxclients; ++i) - { - client_t * client = &g_psvs.clients[i]; - if (client == host_client || client->active || client->connected || client->spawned) - SV_FullClientUpdate(client, &msg); - } - - Con_DPrintf("Client %s started recording. Send full update.\n", host_client->name); - Netchan_CreateFragments(1, &host_client->netchan, &msg); - Netchan_FragSend(&host_client->netchan); -} - -void SV_RunCmd(usercmd_t *ucmd, int random_seed) -{ - usercmd_t cmd = *ucmd; - int i; - edict_t *ent; - trace_t trace; - float frametime; - - if (host_client->ignorecmdtime > realtime) - { - host_client->cmdtime = (double)ucmd->msec / 1000.0 + host_client->cmdtime; - return; - } - - - host_client->ignorecmdtime = 0; - if (cmd.msec > 50) - { - cmd.msec = (byte)(ucmd->msec / 2.0); - SV_RunCmd(&cmd, random_seed); - cmd.msec = (byte)(ucmd->msec / 2.0); - cmd.impulse = 0; - SV_RunCmd(&cmd, random_seed); - return; - } - - - if (!host_client->fakeclient) - SV_SetupMove(host_client); - -#ifdef REHLDS_FIXES - if (sv_usercmd_custom_random_seed.value) - { - float fltTimeNow = float(Sys_FloatTime() * 1000.0); - random_seed = *reinterpret_cast((char *)&fltTimeNow); - } -#endif - - gEntityInterface.pfnCmdStart(sv_player, ucmd, random_seed); - frametime = float(ucmd->msec * 0.001); - host_client->svtimebase = frametime + host_client->svtimebase; - host_client->cmdtime = ucmd->msec / 1000.0 + host_client->cmdtime; - if (ucmd->impulse) - { - sv_player->v.impulse = ucmd->impulse; - - // Disable fullupdate via impulse 204 -#ifndef REHLDS_FIXES - if (ucmd->impulse == 204) - SV_ForceFullClientsUpdate(); -#endif // REHLDS_FIXES - } - sv_player->v.clbasevelocity[0] = 0; - sv_player->v.clbasevelocity[1] = 0; - sv_player->v.clbasevelocity[2] = 0; - sv_player->v.button = ucmd->buttons; -#ifdef REHLDS_FIXES - sv_player->v.light_level = ucmd->lightlevel; -#endif - SV_CheckMovingGround(sv_player, frametime); - pmove->oldangles[0] = sv_player->v.v_angle[0]; - pmove->oldangles[1] = sv_player->v.v_angle[1]; - pmove->oldangles[2] = sv_player->v.v_angle[2]; - if (!sv_player->v.fixangle) - { - sv_player->v.v_angle[0] = ucmd->viewangles[0]; - sv_player->v.v_angle[1] = ucmd->viewangles[1]; - sv_player->v.v_angle[2] = ucmd->viewangles[2]; - } - SV_PlayerRunPreThink(sv_player, (float)host_client->svtimebase); - SV_PlayerRunThink(sv_player, frametime, host_client->svtimebase); - if (Length(sv_player->v.basevelocity) > 0.0) - { - sv_player->v.clbasevelocity[0] = sv_player->v.basevelocity[0]; - sv_player->v.clbasevelocity[1] = sv_player->v.basevelocity[1]; - sv_player->v.clbasevelocity[2] = sv_player->v.basevelocity[2]; - } - - pmove->server = TRUE; - pmove->multiplayer = (g_psvs.maxclients > 1) ? TRUE : FALSE; - pmove->time = float(1000.0 * host_client->svtimebase); - pmove->usehull = (sv_player->v.flags & FL_DUCKING) == FL_DUCKING; - pmove->maxspeed = sv_maxspeed.value; - pmove->clientmaxspeed = sv_player->v.maxspeed; - pmove->flDuckTime = (float)sv_player->v.flDuckTime; - pmove->bInDuck = sv_player->v.bInDuck; - pmove->flTimeStepSound = sv_player->v.flTimeStepSound; - pmove->iStepLeft = sv_player->v.iStepLeft; - pmove->flFallVelocity = sv_player->v.flFallVelocity; - pmove->flSwimTime = (float)sv_player->v.flSwimTime; - pmove->oldbuttons = sv_player->v.oldbuttons; - - Q_strncpy(pmove->physinfo, host_client->physinfo, sizeof(pmove->physinfo) - 1); - pmove->physinfo[sizeof(pmove->physinfo) - 1] = 0; - - pmove->velocity[0] = sv_player->v.velocity[0]; - pmove->velocity[1] = sv_player->v.velocity[1]; - pmove->velocity[2] = sv_player->v.velocity[2]; - - pmove->movedir[0] = sv_player->v.movedir[0]; - pmove->movedir[1] = sv_player->v.movedir[1]; - pmove->movedir[2] = sv_player->v.movedir[2]; - - pmove->angles[0] = sv_player->v.v_angle[0]; - pmove->angles[1] = sv_player->v.v_angle[1]; - pmove->angles[2] = sv_player->v.v_angle[2]; - - pmove->basevelocity[0] = sv_player->v.basevelocity[0]; - pmove->basevelocity[1] = sv_player->v.basevelocity[1]; - pmove->basevelocity[2] = sv_player->v.basevelocity[2]; - - pmove->view_ofs[0] = sv_player->v.view_ofs[0]; - pmove->view_ofs[1] = sv_player->v.view_ofs[1]; - pmove->view_ofs[2] = sv_player->v.view_ofs[2]; - - pmove->punchangle[0] = sv_player->v.punchangle[0]; - pmove->punchangle[1] = sv_player->v.punchangle[1]; - pmove->punchangle[2] = sv_player->v.punchangle[2]; - - pmove->deadflag = sv_player->v.deadflag; - pmove->effects = sv_player->v.effects; - pmove->gravity = sv_player->v.gravity; - pmove->friction = sv_player->v.friction; - pmove->spectator = 0; - pmove->waterjumptime = sv_player->v.teleport_time; - - Q_memcpy(&pmove->cmd, &cmd, sizeof(pmove->cmd)); - - pmove->dead = sv_player->v.health <= 0.0; - pmove->movetype = sv_player->v.movetype; - pmove->flags = sv_player->v.flags; - pmove->player_index = NUM_FOR_EDICT(sv_player) - 1; - - pmove->iuser1 = sv_player->v.iuser1; - pmove->iuser2 = sv_player->v.iuser2; - pmove->iuser3 = sv_player->v.iuser3; - pmove->iuser4 = sv_player->v.iuser4; - pmove->fuser1 = sv_player->v.fuser1; - pmove->fuser2 = sv_player->v.fuser2; - pmove->fuser3 = sv_player->v.fuser3; - pmove->fuser4 = sv_player->v.fuser4; - - pmove->vuser1[0] = sv_player->v.vuser1[0]; - pmove->vuser1[1] = sv_player->v.vuser1[1]; - pmove->vuser1[2] = sv_player->v.vuser1[2]; - - pmove->vuser2[0] = sv_player->v.vuser2[0]; - pmove->vuser2[1] = sv_player->v.vuser2[1]; - pmove->vuser2[2] = sv_player->v.vuser2[2]; - - pmove->vuser3[0] = sv_player->v.vuser3[0]; - pmove->vuser3[1] = sv_player->v.vuser3[1]; - pmove->vuser3[2] = sv_player->v.vuser3[2]; - - pmove->vuser4[0] = sv_player->v.vuser4[0]; - pmove->vuser4[1] = sv_player->v.vuser4[1]; - pmove->vuser4[2] = sv_player->v.vuser4[2]; - - pmove->origin[0] = sv_player->v.origin[0]; - pmove->origin[1] = sv_player->v.origin[1]; - pmove->origin[2] = sv_player->v.origin[2]; - - SV_AddLinksToPM(sv_areanodes, pmove->origin); - - pmove->frametime = frametime; - pmove->runfuncs = TRUE; - pmove->PM_PlaySound = PM_SV_PlaySound; - pmove->PM_TraceTexture = PM_SV_TraceTexture; - pmove->PM_PlaybackEventFull = PM_SV_PlaybackEventFull; - - gEntityInterface.pfnPM_Move(pmove, TRUE); - - sv_player->v.deadflag = pmove->deadflag; - sv_player->v.effects = pmove->effects; - sv_player->v.teleport_time = pmove->waterjumptime; - sv_player->v.waterlevel = pmove->waterlevel; - sv_player->v.watertype = pmove->watertype; - sv_player->v.flags = pmove->flags; - sv_player->v.friction = pmove->friction; - sv_player->v.movetype = pmove->movetype; - sv_player->v.maxspeed = pmove->clientmaxspeed; - sv_player->v.iStepLeft = pmove->iStepLeft; - - sv_player->v.view_ofs[0] = pmove->view_ofs[0]; - sv_player->v.view_ofs[1] = pmove->view_ofs[1]; - sv_player->v.view_ofs[2] = pmove->view_ofs[2]; - - sv_player->v.movedir[0] = pmove->movedir[0]; - sv_player->v.movedir[1] = pmove->movedir[1]; - sv_player->v.movedir[2] = pmove->movedir[2]; - - sv_player->v.punchangle[0] = pmove->punchangle[0]; - sv_player->v.punchangle[1] = pmove->punchangle[1]; - sv_player->v.punchangle[2] = pmove->punchangle[2]; - - if (pmove->onground == -1) - { - sv_player->v.flags &= ~FL_ONGROUND; - } - else - { - sv_player->v.flags |= FL_ONGROUND; - sv_player->v.groundentity = EDICT_NUM(pmove->physents[pmove->onground].info); - } - - sv_player->v.origin[0] = pmove->origin[0]; - sv_player->v.origin[1] = pmove->origin[1]; - sv_player->v.origin[2] = pmove->origin[2]; - - sv_player->v.velocity[0] = pmove->velocity[0]; - sv_player->v.velocity[1] = pmove->velocity[1]; - sv_player->v.velocity[2] = pmove->velocity[2]; - - sv_player->v.basevelocity[0] = pmove->basevelocity[0]; - sv_player->v.basevelocity[1] = pmove->basevelocity[1]; - sv_player->v.basevelocity[2] = pmove->basevelocity[2]; - - if (!sv_player->v.fixangle) - { - sv_player->v.v_angle[0] = pmove->angles[0]; - sv_player->v.v_angle[1] = pmove->angles[1]; - sv_player->v.v_angle[2] = pmove->angles[2]; - sv_player->v.angles[0] = float(-pmove->angles[0] / 3.0); - sv_player->v.angles[1] = pmove->angles[1]; - sv_player->v.angles[2] = pmove->angles[2]; - } - - sv_player->v.bInDuck = pmove->bInDuck; - sv_player->v.flDuckTime = (int)pmove->flDuckTime; - sv_player->v.flTimeStepSound = pmove->flTimeStepSound; - sv_player->v.flFallVelocity = pmove->flFallVelocity; - sv_player->v.flSwimTime = (int)pmove->flSwimTime; - sv_player->v.oldbuttons = pmove->cmd.buttons; - - sv_player->v.iuser1 = pmove->iuser1; - sv_player->v.iuser2 = pmove->iuser2; - sv_player->v.iuser3 = pmove->iuser3; - sv_player->v.iuser4 = pmove->iuser4; - sv_player->v.fuser1 = pmove->fuser1; - sv_player->v.fuser2 = pmove->fuser2; - sv_player->v.fuser3 = pmove->fuser3; - sv_player->v.fuser4 = pmove->fuser4; - - sv_player->v.vuser1[0] = pmove->vuser1[0]; - sv_player->v.vuser1[1] = pmove->vuser1[1]; - sv_player->v.vuser1[2] = pmove->vuser1[2]; - - sv_player->v.vuser2[0] = pmove->vuser2[0]; - sv_player->v.vuser2[1] = pmove->vuser2[1]; - sv_player->v.vuser2[2] = pmove->vuser2[2]; - - sv_player->v.vuser3[0] = pmove->vuser3[0]; - sv_player->v.vuser3[1] = pmove->vuser3[1]; - sv_player->v.vuser3[2] = pmove->vuser3[2]; - - sv_player->v.vuser4[0] = pmove->vuser4[0]; - sv_player->v.vuser4[1] = pmove->vuser4[1]; - sv_player->v.vuser4[2] = pmove->vuser4[2]; - - SetMinMaxSize(sv_player, player_mins[pmove->usehull], player_maxs[pmove->usehull], 0); - if (host_client->edict->v.solid) - { - SV_LinkEdict(sv_player, TRUE); - vec3_t vel; - - vel[0] = sv_player->v.velocity[0]; - vel[1] = sv_player->v.velocity[1]; - vel[2] = sv_player->v.velocity[2]; - for (i = 0; i < pmove->numtouch; ++i) - { - pmtrace_t *tr = &pmove->touchindex[i]; - ent = EDICT_NUM(pmove->physents[tr->ent].info); - SV_ConvertPMTrace(&trace, tr, ent); - sv_player->v.velocity[0] = tr->deltavelocity[0]; - sv_player->v.velocity[1] = tr->deltavelocity[1]; - sv_player->v.velocity[2] = tr->deltavelocity[2]; - SV_Impact(ent, sv_player, &trace); - } - sv_player->v.velocity[0] = vel[0]; - sv_player->v.velocity[1] = vel[1]; - sv_player->v.velocity[2] = vel[2]; - } - - gGlobalVariables.time = (float)host_client->svtimebase; - gGlobalVariables.frametime = frametime; - gEntityInterface.pfnPlayerPostThink(sv_player); - gEntityInterface.pfnCmdEnd(sv_player); - - if (!host_client->fakeclient) - SV_RestoreMove(host_client); -} - -int SV_ValidateClientCommand(char *pszCommand) -{ - const char *p; - int i = 0; - - COM_Parse(pszCommand); - while ((p = clcommands[i]) != NULL) - { - if (!Q_stricmp(com_token, p)) - { - return 1; - } - i++; - } - return 0; -} - -float SV_CalcClientTime(client_t *cl) -{ - float minping; - float maxping; - int backtrack; - - float ping = 0.0; - int count = 0; - backtrack = (int)sv_unlagsamples.value; - - if (backtrack < 1) - backtrack = 1; - - if (backtrack >= (SV_UPDATE_BACKUP <= 16 ? SV_UPDATE_BACKUP : 16)) - backtrack = (SV_UPDATE_BACKUP <= 16 ? SV_UPDATE_BACKUP : 16); - - if (backtrack <= 0) - return 0.0f; - - for (int i = 0; i < backtrack; i++) - { - client_frame_t *frame = &cl->frames[SV_UPDATE_MASK & (cl->netchan.incoming_acknowledged - i)]; - if (frame->ping_time <= 0.0f) - continue; - - ++count; - ping += frame->ping_time; - } - - if (!count) - return 0.0f; - - minping = 9999.0; - maxping = -9999.0; - ping /= count; - - for (int i = 0; i < (SV_UPDATE_BACKUP <= 4 ? SV_UPDATE_BACKUP : 4); i++) - { - client_frame_t *frame = &cl->frames[SV_UPDATE_MASK & (cl->netchan.incoming_acknowledged - i)]; - if (frame->ping_time <= 0.0f) - continue; - - if (frame->ping_time < minping) - minping = frame->ping_time; - - if (frame->ping_time > maxping) - maxping = frame->ping_time; - } - - if (maxping < minping || fabs(maxping - minping) <= 0.2) - return ping; - - return 0.0f; -} - -void SV_ComputeLatency(client_t *cl) -{ - cl->latency = SV_CalcClientTime(cl); -} - -int SV_UnlagCheckTeleport(vec_t *v1, vec_t *v2) -{ - for (int i = 0; i < 3; i++) - { - if (fabs(v1[i] - v2[i]) > 128) - return 1; - } - - return 0; -} - -void SV_GetTrueOrigin(int player, vec_t *origin) -{ - if (!host_client->lw || !host_client->lc) - return; - - if (sv_unlag.value == 0 || g_psvs.maxclients <= 1 || !host_client->active) - return; - - if (player < 0 || player >= g_psvs.maxclients) - return; - - if (truepositions[player].active && truepositions[player].needrelink) - { - origin[0] = truepositions[player].oldorg[0]; - origin[1] = truepositions[player].oldorg[1]; - origin[2] = truepositions[player].oldorg[2]; - } -} - -void SV_GetTrueMinMax(int player, float **fmin, float **fmax) -{ - if (!host_client->lw || !host_client->lc) - return; - - if (sv_unlag.value == 0.0f || g_psvs.maxclients <= 1) - return; - - if (!host_client->active || player < 0 || player >= g_psvs.maxclients) - return; - - if (truepositions[player].active && truepositions[player].needrelink) - { - *fmin = truepositions[player].oldabsmin; - *fmax = truepositions[player].oldabsmax; - } -} - -entity_state_t *SV_FindEntInPack(int index, packet_entities_t *pack) -{ - if (pack->num_entities <= 0) - return NULL; - - for (int i = 0; i < pack->num_entities; i++) - { - if (pack->entities[i].number == index) - return &pack->entities[i]; - } - - return NULL; -} - -void SV_SetupMove(client_t *_host_client) -{ - struct client_s *cl; - float cl_interptime; - client_frame_t *nextFrame; - entity_state_t *state; - sv_adjusted_positions_t *pos; - float frac; - entity_state_t *pnextstate; - int i; - client_frame_t *frame; - vec3_t origin; - vec3_t delta; - - -#ifdef REHLDS_FIXES - double targettime; // FP precision fix -#else - float targettime; -#endif // REHLDS_FIXES - - Q_memset(truepositions, 0, sizeof(truepositions)); - nofind = 1; - if (!gEntityInterface.pfnAllowLagCompensation()) - return; - - if (sv_unlag.value == 0.0f || !_host_client->lw || !_host_client->lc) - return; - - if (g_psvs.maxclients <= 1 || !_host_client->active) - return; - - nofind = 0; - for (int i = 0; i < g_psvs.maxclients; i++) - { - cl = &g_psvs.clients[i]; - if (cl == _host_client || !cl->active) - continue; - - truepositions[i].oldorg[0] = cl->edict->v.origin[0]; - truepositions[i].oldorg[1] = cl->edict->v.origin[1]; - truepositions[i].oldorg[2] = cl->edict->v.origin[2]; - truepositions[i].oldabsmin[0] = cl->edict->v.absmin[0]; - truepositions[i].oldabsmin[1] = cl->edict->v.absmin[1]; - truepositions[i].oldabsmin[2] = cl->edict->v.absmin[2]; - truepositions[i].oldabsmax[0] = cl->edict->v.absmax[0]; - truepositions[i].oldabsmax[1] = cl->edict->v.absmax[1]; - truepositions[i].active = 1; - truepositions[i].oldabsmax[2] = cl->edict->v.absmax[2]; - } - - float clientLatency = _host_client->latency; - if (clientLatency > 1.5) - clientLatency = 1.5f; - - if (sv_maxunlag.value != 0.0f) - { - if (sv_maxunlag.value < 0.0) - Cvar_SetValue("sv_maxunlag", 0.0); - - if (clientLatency >= sv_maxunlag.value) - clientLatency = sv_maxunlag.value; - } - - cl_interptime = _host_client->lastcmd.lerp_msec / 1000.0f; - - if (cl_interptime > 0.1) - cl_interptime = 0.1f; - - if (_host_client->next_messageinterval > cl_interptime) - cl_interptime = (float) _host_client->next_messageinterval; - -#ifdef REHLDS_FIXES - // FP Precision fix (targettime is double there, not float) - targettime = realtime - clientLatency - cl_interptime + sv_unlagpush.value; - if (targettime > realtime) - targettime = realtime; -#else - targettime = float(realtime - clientLatency - cl_interptime + sv_unlagpush.value); - if (targettime > realtime) - targettime = float(realtime); -#endif // REHLDS_FIXES - - if (SV_UPDATE_BACKUP <= 0) - { - Q_memset(truepositions, 0, sizeof(truepositions)); - nofind = 1; - return; - } - - frame = nextFrame = NULL; - for (i = 0; i < SV_UPDATE_BACKUP; i++, frame = nextFrame) - { - nextFrame = &_host_client->frames[SV_UPDATE_MASK & (_host_client->netchan.outgoing_sequence + ~i)]; - for (int j = 0; j < nextFrame->entities.num_entities; j++) - { - state = &nextFrame->entities.entities[j]; - -#ifdef REHLDS_OPT_PEDANTIC - if (state->number <= 0) - continue; - - if (state->number > g_psvs.maxclients) - break; // players are always in the beginning of the list, no need to look more -#else - if (state->number <= 0 || state->number > g_psvs.maxclients) - continue; -#endif - - pos = &truepositions[state->number - 1]; - if (pos->deadflag) - continue; - - - if (state->health <= 0) - pos->deadflag = 1; - - if (state->effects & EF_NOINTERP) - pos->deadflag = 1; - - if (pos->temp_org_setflag) - { - if (SV_UnlagCheckTeleport(state->origin, pos->temp_org)) - pos->deadflag = 1; - } - else - { - pos->temp_org_setflag = 1; - } - - pos->temp_org[0] = state->origin[0]; - pos->temp_org[1] = state->origin[1]; - pos->temp_org[2] = state->origin[2]; - } - - if (targettime > nextFrame->senttime) - break; - } - - if ( i >= SV_UPDATE_BACKUP || targettime - nextFrame->senttime > 1.0) - { - Q_memset(truepositions, 0, sizeof(truepositions)); - nofind = 1; - return; - } - - if (frame) - { - float timeDiff = float(frame->senttime - nextFrame->senttime); - if (timeDiff == 0.0) - frac = 0.0; - else - { - frac = float((targettime - nextFrame->senttime) / timeDiff); - if (frac <= 1.0) - { - if (frac < 0.0) - frac = 0.0; - } - else - frac = 1.0; - } - } - else - { - frame = nextFrame; - frac = 0.0; - } - - for (i = 0; i < nextFrame->entities.num_entities; i++) - { - state = &nextFrame->entities.entities[i]; - if (state->number <= 0 || state->number > g_psvs.maxclients) - continue; - - cl = &g_psvs.clients[state->number - 1]; - if (cl == _host_client || !cl->active) - continue; - - pos = &truepositions[state->number - 1]; - if (pos->deadflag) - continue; - - if (!pos->active) - { - Con_DPrintf("tried to store off position of bogus player %i/%s\n", i, cl->name); - continue; - } - - pnextstate = SV_FindEntInPack(state->number, &frame->entities); - - if (pnextstate) - { - delta[0] = pnextstate->origin[0] - state->origin[0]; - delta[1] = pnextstate->origin[1] - state->origin[1]; - delta[2] = pnextstate->origin[2] - state->origin[2]; - VectorMA(state->origin, frac, delta, origin); - } - else - { - origin[0] = state->origin[0]; - origin[1] = state->origin[1]; - origin[2] = state->origin[2]; - } - pos->neworg[0] = origin[0]; - pos->neworg[1] = origin[1]; - pos->neworg[2] = origin[2]; - pos->initial_correction_org[0] = origin[0]; - pos->initial_correction_org[1] = origin[1]; - pos->initial_correction_org[2] = origin[2]; - if (!VectorCompare(origin, cl->edict->v.origin)) - { - cl->edict->v.origin[0] = origin[0]; - cl->edict->v.origin[1] = origin[1]; - cl->edict->v.origin[2] = origin[2]; - SV_LinkEdict(cl->edict, FALSE); - pos->needrelink = 1; - } - } -} - -void SV_RestoreMove(client_t *_host_client) -{ - sv_adjusted_positions_t *pos; - client_t *cli; - - if (nofind) - { - nofind = 0; - return; - } - - if (!gEntityInterface.pfnAllowLagCompensation()) - return; - - if (g_psvs.maxclients <= 1 || sv_unlag.value == 0.0) - return; - - if (!_host_client->lw || !_host_client->lc || !_host_client->active) - return; - - for (int i = 0; i < g_psvs.maxclients; i++) - { - cli = &g_psvs.clients[i]; - pos = &truepositions[i]; - - if (cli == _host_client ||! cli->active) - continue; - - if (VectorCompare(pos->neworg, pos->oldorg) || !pos->needrelink) - continue; - - if (!pos->active) - { - Con_DPrintf("SV_RestoreMove: Tried to restore 'inactive' player %i/%s\n", i, &cli->name[4]); - continue; - } - - if (VectorCompare(pos->initial_correction_org, cli->edict->v.origin)) - { - cli->edict->v.origin[0] = pos->oldorg[0]; - cli->edict->v.origin[1] = pos->oldorg[1]; - cli->edict->v.origin[2] = pos->oldorg[2]; - SV_LinkEdict(cli->edict, FALSE); - } - } -} - -void SV_ParseStringCommand(client_t *pSenderClient) -{ - //check string commands rate for this player -#ifdef REHLDS_FIXES - g_StringCommandsRateLimiter.StringCommandIssued(pSenderClient - g_psvs.clients); - - if (!pSenderClient->connected) { - return; //return if player was kicked - } -#endif - - char *s = MSG_ReadString(); - int ret = SV_ValidateClientCommand(s); - switch (ret) - { - case 0: -#ifndef REHLDS_OPT_PEDANTIC - if (Q_strlen(s) > 127) -#endif - { - s[127] = 0; - } - Cmd_TokenizeString(s); - gEntityInterface.pfnClientCommand(sv_player); - break; - case 1: - Cmd_ExecuteString(s, src_client); - break; - case 2: // TODO: Check not used path - Cbuf_InsertText(s); - break; - } -} - -void SV_ParseDelta(client_t *pSenderClient) -{ - host_client->delta_sequence = MSG_ReadByte(); -} - -void EXT_FUNC SV_EstablishTimeBase_mod(IGameClient *cl, usercmd_t *cmds, int dropped, int numbackup, int numcmds) -{ - SV_EstablishTimeBase_internal(cl->GetClient(), cmds, dropped, numbackup, numcmds); -} - -void SV_EstablishTimeBase(client_t *cl, usercmd_t *cmds, int dropped, int numbackup, int numcmds) -{ - return g_RehldsHookchains.m_SV_EstablishTimeBase.callChain(SV_EstablishTimeBase_mod, GetRehldsApiClient(cl), cmds, dropped, numbackup, numcmds); -} - -void SV_EstablishTimeBase_internal(client_t *cl, usercmd_t *cmds, int dropped, int numbackup, int numcmds) -{ - int i; - double runcmd_time = 0.0; - double time_at_end = 0.0; - constexpr int MAX_DROPPED_CMDS = 24; - - // If we haven't dropped too many packets, then run some commands - if (dropped < MAX_DROPPED_CMDS) - { - if (dropped > numbackup) - { - // Con_Printf("%s: lost %i cmds\n", __func__, dropped - numbackup); - } - - int droppedcmds = dropped; - - // Run the last known cmd for each dropped cmd we don't have a backup for - while (droppedcmds > numbackup) - { - runcmd_time += cl->lastcmd.msec / 1000.0; - droppedcmds--; - } - - // Now run the "history" commands if we still have dropped packets - while (droppedcmds > 0) - { - int cmdnum = numcmds + droppedcmds - 1; - runcmd_time += cmds[cmdnum].msec / 1000.0; - droppedcmds--; - } - } - - // Now run any new command(s). Go backward because the most recent command is at index 0 - for (i = numcmds - 1; i >= 0; i--) - { - time_at_end += cmds[i].msec / 1000.0; - } - - cl->svtimebase = host_frametime + g_psv.time - (time_at_end + runcmd_time); -} - -void SV_ParseMove(client_t *pSenderClient) -{ - client_frame_t *frame; - int placeholder; - int mlen; - unsigned int packetLossByte; - int numcmds; - int totalcmds; - byte cbpktchecksum; - usercmd_t *cmd; - usercmd_t cmds[64]; - usercmd_t cmdNull; - float packet_loss; - byte cbchecksum; - int numbackup; - - if (g_balreadymoved) - { - msg_badread = 1; - return; - } - g_balreadymoved = 1; - - frame = &host_client->frames[SV_UPDATE_MASK & host_client->netchan.incoming_acknowledged]; - Q_memset(&cmdNull, 0, sizeof(cmdNull)); - - placeholder = msg_readcount + 1; - mlen = MSG_ReadByte(); - cbchecksum = MSG_ReadByte(); - - if (mlen <= 0 || !SZ_HasSpaceToRead(&net_message, mlen)) - { - msg_badread = TRUE; - Con_DPrintf("%s: %s:%s invalid length: %d\n", __func__, host_client->name, NET_AdrToString(host_client->netchan.remote_address), mlen); - SV_DropClient(host_client, FALSE, "Invalid length"); - return; - } - - COM_UnMunge(&net_message.data[placeholder + 1], mlen, host_client->netchan.incoming_sequence); - - packetLossByte = MSG_ReadByte(); - numbackup = MSG_ReadByte(); - numcmds = MSG_ReadByte(); - - packet_loss = float(packetLossByte & 0x7F); - pSenderClient->m_bLoopback = (packetLossByte >> 7) & 1; - totalcmds = numcmds + numbackup; - net_drop += 1 - numcmds; - if (totalcmds < 0 || totalcmds >= CMD_MAXBACKUP - 1) - { - Con_Printf("SV_ReadClientMessage: too many cmds %i sent for %s/%s\n", totalcmds, host_client->name, NET_AdrToString(host_client->netchan.remote_address)); - SV_DropClient(host_client, FALSE, "CMD_MAXBACKUP hit"); - msg_badread = 1; - return; - } - - usercmd_t* from = &cmdNull; - for (int i = totalcmds - 1; i >= 0; i--) - { - MSG_ReadUsercmd(&cmds[i], from); - from = &cmds[i]; - } - - if (!g_psv.active || !(host_client->active || host_client->spawned)) - return; - - if (msg_badread) - { - Con_Printf("Client %s:%s sent a bogus command packet\n", host_client->name, NET_AdrToString(host_client->netchan.remote_address)); - return; - } - - cbpktchecksum = COM_BlockSequenceCRCByte(&net_message.data[placeholder + 1], msg_readcount - placeholder - 1, host_client->netchan.incoming_sequence); - if (cbpktchecksum != cbchecksum) - { - Con_DPrintf("Failed command checksum for %s:%s\n", host_client->name, NET_AdrToString(host_client->netchan.remote_address)); - msg_badread = 1; - return; - } - - host_client->packet_loss = packet_loss; - if (!g_psv.paused && (g_psvs.maxclients > 1 || !key_dest) && !(sv_player->v.flags & FL_FROZEN)) - { - sv_player->v.v_angle[0] = cmds[0].viewangles[0]; - sv_player->v.v_angle[1] = cmds[0].viewangles[1]; - sv_player->v.v_angle[2] = cmds[0].viewangles[2]; - } - else - { - for (int i = 0; i < numcmds; i++) - { - cmd = &cmds[i]; - cmd->msec = 0; - cmd->forwardmove = 0; - cmd->sidemove = 0; - cmd->upmove = 0; - cmd->buttons = 0; - - if (sv_player->v.flags & FL_FROZEN) - cmd->impulse = 0; - - cmd->viewangles[0] = sv_player->v.v_angle[0]; - cmd->viewangles[1] = sv_player->v.v_angle[1]; - cmd->viewangles[2] = sv_player->v.v_angle[2]; - } - - net_drop = 0; - } - - //check move commands rate for this player -#ifdef REHLDS_FIXES - int numCmdsToIssue = numcmds; - if (net_drop > 0) { - numCmdsToIssue += net_drop; - } - g_MoveCommandRateLimiter.MoveCommandsIssued(host_client - g_psvs.clients, numCmdsToIssue); - - if (!host_client->connected) { - return; //return if player was kicked - } -#endif - -#ifndef REHLDS_FIXES - // dup and more correct in SV_RunCmd - sv_player->v.button = cmds[0].buttons; - sv_player->v.light_level = cmds[0].lightlevel; -#endif - SV_EstablishTimeBase(host_client, cmds, net_drop, numbackup, numcmds); - if (net_drop < 24) - { - while (net_drop > numbackup) - { - SV_RunCmd(&host_client->lastcmd, 0); - net_drop--; - } - - while (net_drop > 0) - { - SV_RunCmd(&cmds[numcmds + net_drop - 1], host_client->netchan.incoming_sequence - (numcmds + net_drop - 1)); - net_drop--; - } - - } - - for (int i = numcmds - 1; i >= 0; i--) - { - SV_RunCmd(&cmds[i], host_client->netchan.incoming_sequence - i); - } - -#ifdef REHLDS_FIXES - if (numcmds) - host_client->lastcmd = cmds[numcmds - 1]; - else if (numbackup) - host_client->lastcmd = cmds[0]; -#else - host_client->lastcmd = cmds[0]; -#endif - - frame->ping_time -= float(host_client->lastcmd.msec * 0.5 / 1000.0); - if (frame->ping_time < 0.0) - frame->ping_time = 0; - - if (sv_player->v.animtime > host_frametime + g_psv.time) - sv_player->v.animtime = float(host_frametime + g_psv.time); -} - -void SV_ParseVoiceData(client_t *cl) -{ - char chReceived[4096]; - int iClient = cl - g_psvs.clients; - unsigned int nDataLength = MSG_ReadShort(); - if (nDataLength > sizeof(chReceived)) - { - Con_DPrintf("SV_ParseVoiceData: invalid incoming packet.\n"); - SV_DropClient(cl, FALSE, "Invalid voice data\n"); - return; - } - - MSG_ReadBuf(nDataLength, chReceived); - cl->m_lastvoicetime = g_psv.time; - - if (sv_voiceenable.value == 0.0f) - return; - - for (int i = 0; i < g_psvs.maxclients; i++) - { - client_t *pDestClient = &g_psvs.clients[i]; - if (!((1 << (i & 0x1F)) & cl->m_VoiceStreams[i >> 5]) && i != iClient) - continue; - - if (!pDestClient->active && !pDestClient->connected && i != iClient) - continue; - - int nSendLength = nDataLength; - if (i == iClient && !pDestClient->m_bLoopback) - nSendLength = 0; - - if (pDestClient->datagram.cursize + nSendLength + 6 < pDestClient->datagram.maxsize) - { - MSG_WriteByte(&pDestClient->datagram, svc_voicedata); - MSG_WriteByte(&pDestClient->datagram, iClient); - MSG_WriteShort(&pDestClient->datagram, nSendLength); - MSG_WriteBuf(&pDestClient->datagram, nSendLength, chReceived); - } - } -} - -void SV_IgnoreHLTV(client_t *cl) -{ -} - -void SV_ParseCvarValue(client_t *cl) -{ - char *value; - value = MSG_ReadString(); - if (gNewDLLFunctions.pfnCvarValue) - gNewDLLFunctions.pfnCvarValue(cl->edict, value); - - Con_DPrintf("Cvar query response: name:%s, value:%s\n", cl->name, value); -} - -void SV_ParseCvarValue2(client_t *cl) -{ - int requestID = MSG_ReadLong(); - - char cvarName[255]; - Q_strncpy(cvarName, MSG_ReadString(), sizeof(cvarName)); - cvarName[sizeof(cvarName) - 1] = 0; - - char* value = MSG_ReadString(); - - if (gNewDLLFunctions.pfnCvarValue2) - gNewDLLFunctions.pfnCvarValue2(cl->edict, requestID, cvarName, value); - - Con_DPrintf("Cvar query response: name:%s, request ID %d, cvar:%s, value:%s\n", cl->name, requestID, cvarName, value); -} - -void EXT_FUNC SV_HandleClientMessage_api(IGameClient* client, uint8 opcode) { - client_t* cl = client->GetClient(); - if (opcode < clc_bad || opcode > clc_cvarvalue2) - { - // TODO: Are we forced to use msg_badread for break the loop. - static_assert(REHLDS_API_VERSION_MAJOR <= 3, "Bump major API DETECTED!! You shall rework the hookchain, make function returnable"); - msg_badread = 1; - - Con_Printf("SV_ReadClientMessage: unknown command char (%d)\n", opcode); - SV_DropClient(cl, FALSE, "Bad command character in client command"); - return; - } - -#ifdef REHLDS_FIXES - // Save current name of the client before a possible kick - char name[32]; - Q_strlcpy(name, host_client->name); -#endif - - void(*func)(client_t *) = sv_clcfuncs[opcode].pfnParse; - if (func) - func(cl); - -#ifdef REHLDS_FIXES - if (msg_badread) - { - Con_Printf("SV_ReadClientMessage: badread on %s, opcode %s\n", name, sv_clcfuncs[opcode].pszname); - } -#endif - -} - -void SV_ExecuteClientMessage(client_t *cl) -{ - g_balreadymoved = 0; - client_frame_t * frame = &cl->frames[SV_UPDATE_MASK & cl->netchan.incoming_acknowledged]; - frame->ping_time = realtime - frame->senttime - cl->next_messageinterval; - if (frame->senttime == 0.0) - frame->ping_time = 0; - - if (realtime - cl->connection_started < 2.0 && frame->ping_time > 0.0) - frame->ping_time = 0; - - SV_ComputeLatency(cl); - host_client = cl; - sv_player = cl->edict; - cl->delta_sequence = -1; - pmove = &g_svmove; - IGameClient* apiClient = GetRehldsApiClient(cl); - - while (1) - { - if (msg_badread) - { -#ifdef REHLDS_FIXES - Con_Printf("SV_ReadClientMessage: badread on %s\n", host_client->name); - if (host_client->active) - SV_ClientPrintf("Badread\n"); -#else // REHLDS_FIXES - Con_Printf("SV_ReadClientMessage: badread\n"); -#endif // REHLDS_FIXES - return; - } - - int c = MSG_ReadByte(); - if (c == -1) - return; - - g_RehldsHookchains.m_HandleNetCommand.callChain(SV_HandleClientMessage_api, apiClient, c); - -#ifdef REHLDS_FIXES - // FIXED: Don't handle remaining packets if got dropclient above - if (!cl->connected && !cl->active && !cl->spawned) - break; -#endif // REHLDS_FIXES - } -} - -qboolean SV_SetPlayer(int idnum) -{ - for (int i = 0; i < g_psvs.maxclients; i++) - { - client_t *cl = &g_psvs.clients[i]; - if (!cl->spawned || !cl->active || !cl->connected) - continue; - - if (cl->userid == idnum) - { - host_client = cl; - sv_player = cl->edict; - return 1; - } - } - - Con_Printf("Userid %i is not on the server\n", idnum); - return 0; -} - -void SV_ShowServerinfo_f(void) -{ - if (cmd_source == src_command) - { - Cmd_ForwardToServer(); - } - else - { -#ifdef REHLDS_FIXES - // fix print message client console - SV_ClientPrintf(Info_Serverinfo()); -#else - Info_Print(Info_Serverinfo()); -#endif // REHLDS_FIXES - } -} - -void SV_SendEnts_f(void) -{ - if (cmd_source == src_command) - { - Cmd_ForwardToServer(); - } - else - { - if (host_client->active && host_client->spawned) - { - if (host_client->connected) - { - host_client->fully_connected = TRUE; - -#ifdef REHLDS_FIXES - // See SV_CheckFile function - if (sv_delayed_spray_upload.value) - { - resource_t *res = host_client->resourcesneeded.pNext; - if (res != &host_client->resourcesneeded) - { - // TODO: all this is already checked earlier - if (res->ucFlags & RES_WASMISSING && res->type == t_decal && res->ucFlags & RES_CUSTOM) - { - if (sv_rehlds_force_dlmax.value) - { - MSG_WriteByte(&host_client->netchan.message, svc_stufftext); - MSG_WriteString(&host_client->netchan.message, va("cl_dlmax %i\n", FRAGMENT_MAX_SIZE)); - } - - MSG_WriteByte(&host_client->netchan.message, svc_stufftext); - MSG_WriteString(&host_client->netchan.message, va("upload !MD5%s\n", MD5_Print(res->rgucMD5_hash))); - } - } - } -#endif // REHLDS_FIXES - } - } - } -} - -void SV_FullUpdate_f(void) -{ - int entIndex; - float ltime; - - if (cmd_source == src_command) - { - Cmd_ForwardToServer(); - return; - } - - if (host_client->active) - { - entIndex = IndexOfEdict(host_client->edict); - if (s_LastFullUpdate[entIndex] > g_psv.time) - s_LastFullUpdate[entIndex] = 0; - - ltime = g_psv.time - s_LastFullUpdate[entIndex]; - if (ltime <= 0.0) - ltime = 0.0; - - if (ltime < 0.45 && g_psv.time > 0.45) - { - Con_DPrintf( - "%s is spamming fullupdate: (%f) (%f) (%f)\n", - host_client->name, - g_psv.time, - s_LastFullUpdate[entIndex], - ltime); - return; - } - s_LastFullUpdate[entIndex] = g_psv.time; - -#ifdef REHLDS_FIXES - // it's not need until not active - SV_ForceFullClientsUpdate(); - gEntityInterface.pfnClientCommand( sv_player ); -#endif // REHLDS_FIXES - } - -#ifndef REHLDS_FIXES - SV_ForceFullClientsUpdate(); - gEntityInterface.pfnClientCommand(sv_player); -#endif // REHLDS_FIXES -}