//++ BulliT //Most parts written by David "Nighthawk" Flor (dflor@mach3.com) for the mod Opera (http://www.halflife.net/opera) //Parts of code from Valve Software mdlviewer (CalcBonePosition). #include "hud.h" #include "cl_util.h" #include "const.h" #include "parsemsg.h" #include "com_model.h" #include "studio.h" #include "com_weapons.h" #include "agmodel.h" #ifdef AG_USE_CHEATPROTECTION void CalcBonePosition(int frame, mstudiobone_t *pbone, mstudioanim_t *panim, float *pos); extern int g_iPure; ////////////////////////////////////////////////////////////////////// // Construction/Destruction ////////////////////////////////////////////////////////////////////// AgModel::AgModel() { m_vMinBounds = Vector(0,0,0); m_vMaxBounds = Vector(0,0,0); m_iVertexCount = 0; m_vMinBone = Vector(0,0,0); m_vMaxBone = Vector(0,0,0); m_iBoneCount = 0; m_bCorrupt = false; m_bFoundAndChecked = false; } AgModel::~AgModel() { } void AgModel::AddVertex( const Vector &vPoint ) { if (m_iVertexCount == 0) { m_vMinBounds = m_vMaxBounds = vPoint; } else { m_vMinBounds.x = min( m_vMinBounds.x, vPoint.x ); m_vMinBounds.y = min( m_vMinBounds.y, vPoint.y ); m_vMinBounds.z = min( m_vMinBounds.z, vPoint.z ); m_vMaxBounds.x = max( m_vMaxBounds.x, vPoint.x ); m_vMaxBounds.y = max( m_vMaxBounds.y, vPoint.y ); m_vMaxBounds.z = max( m_vMaxBounds.z, vPoint.z ); } m_iVertexCount++; } void AgModel::AddBone( const Vector &vPoint ) { if (m_iBoneCount == 0) { m_vMinBone = m_vMaxBone = vPoint; } else { m_vMinBone.x = min( m_vMinBone.x, vPoint.x ); m_vMinBone.y = min( m_vMinBone.y, vPoint.y ); m_vMinBone.z = min( m_vMinBone.z, vPoint.z ); m_vMaxBone.x = max( m_vMaxBone.x, vPoint.x ); m_vMaxBone.y = max( m_vMaxBone.y, vPoint.y ); m_vMaxBone.z = max( m_vMaxBone.z, vPoint.z ); } m_iBoneCount++; } void AgModel::AddBonesToVertices( void ) { Vector vAdjust; if (m_iBoneCount > 0) { vAdjust = (m_vMaxBone - m_vMinBone); AddVertex( vAdjust / 2 ); AddVertex( -(vAdjust / 2) ); m_vMinBone = m_vMaxBone = Vector(0,0,0); m_iBoneCount = 0; } } void AgModel::ReadModel(const char *szModelName) { char *pBuffer; char *pTempBuffer; char szFullName[ _MAX_PATH ]; float flBone[3]; strcpy( szFullName, szModelName ); pBuffer = (char*)gEngfuncs.COM_LoadFile( szFullName, 5, NULL ); if (pBuffer) { studiohdr_t *pHeader; mstudiobodyparts_t *pBodyParts; mstudiomodel_t *pModel; long iCnt; long iModelCnt, iModels; long iVert, iVertCnt; vec3_t *pVert; mstudiobone_t *pBone; long iBoneCnt, iBones; mstudioseqdesc_t *pSequence; long iSequenceCnt, iSequences; mstudioanim_t *pAnim; long iFrameCnt, iFrames; pHeader = (studiohdr_t *)pBuffer; if (10 == pHeader->version) { pTempBuffer = (pBuffer + pHeader->bodypartindex); pBodyParts = (mstudiobodyparts_t *)pTempBuffer; iModels = 0; for (iCnt = 0; iCnt < pHeader->numbodyparts; iCnt++) iModels += pBodyParts[iCnt].nummodels; pTempBuffer += (pHeader->numbodyparts * sizeof(mstudiobodyparts_t)); pModel = (mstudiomodel_t *)pTempBuffer; for (iModelCnt = 0; iModelCnt < iModels; iModelCnt++) { iVert = pModel[iModelCnt].numverts; pVert = (vec3_t *)(pBuffer + pModel[iModelCnt].vertindex); for (iVertCnt = 0; iVertCnt < iVert; iVertCnt++) { AddVertex( pVert[iVertCnt] ); } } pBone = (mstudiobone_t *)(pBuffer + pHeader->boneindex); iBones = pHeader->numbones; pSequence = (mstudioseqdesc_t *)(pBuffer + pHeader->seqindex); iSequences = pHeader->numseq; for (iSequenceCnt = 0; iSequenceCnt < iSequences; iSequenceCnt++) { iFrames = pSequence[iSequenceCnt].numframes; pTempBuffer = (pBuffer + pSequence[iSequenceCnt].animindex); pAnim = (mstudioanim_t *)pTempBuffer; for (iBoneCnt = 0; iBoneCnt < iBones; iBoneCnt++) { for (iFrameCnt = 0; iFrameCnt < iFrames; iFrameCnt++) { CalcBonePosition( iFrameCnt, pBone + iBoneCnt, pAnim, flBone ); AddBone( flBone ); } } AddBonesToVertices(); } m_bFoundAndChecked = true; } else { m_bCorrupt = true; } gEngfuncs.COM_FreeFile( pBuffer ); } } void CalcBonePosition( int frame, mstudiobone_t *pbone, mstudioanim_t *panim, float *pos ) { float s = 0; int j, k; mstudioanimvalue_t *panimvalue; for (j = 0; j < 3; j++) { pos[j] = pbone->value[j]; // default; if (panim->offset[j] != 0) { panimvalue = (mstudioanimvalue_t *)((byte *)panim + panim->offset[j]); k = frame; // find span of values that includes the frame we want while (panimvalue->num.total <= k) { k -= panimvalue->num.total; panimvalue += panimvalue->num.valid + 1; } // if we're inside the span if (panimvalue->num.valid > k) { // and there's more data in the span if (panimvalue->num.valid > k + 1) { pos[j] += (panimvalue[k+1].value * (1.0 - s) + s * panimvalue[k+2].value) * pbone->scale[j]; } else { pos[j] += panimvalue[k+1].value * pbone->scale[j]; } } else { // are we at the end of the repeating values section and there's another section with data? if (panimvalue->num.total <= k + 1) { pos[j] += (panimvalue[panimvalue->num.valid].value * (1.0 - s) + s * panimvalue[panimvalue->num.valid + 2].value) * pbone->scale[j]; } else { pos[j] += panimvalue[panimvalue->num.valid].value * pbone->scale[j]; } } } } } bool AgModel::CheckModel(const char* szModelName) { try { ReadModel(szModelName); } catch(...) { m_bCorrupt = true; } if (m_bCorrupt) { char szMessage[256]; sprintf(szMessage,"Server enforces model check and %s seems to be corrupt.\n",szModelName); AgLog(szMessage); ConsolePrint(szMessage); #ifdef _DEBUG return true; #else return false; #endif } Vector vMaxBounds = Vector(0,0,0); Vector vBounds = m_vMaxBounds - m_vMinBounds; if ( !strnicmp( szModelName, "/models/player", 14) ) { if (0 < g_iPure) vMaxBounds = Vector( 78, 30, 98 ); else vMaxBounds = Vector( 105, 105, 105 ); //Big fucking models allowed.. } else if ( !strnicmp( szModelName, "/models/p_", 9 ) ) vMaxBounds = Vector( 42, 21, 60 ); else if ( !strnicmp( szModelName, "/models/w_", 9 ) ) vMaxBounds = Vector( 82, 69, 76); else if ( !strnicmp( szModelName, "/models/v_", 9 ) ) vMaxBounds = Vector( 46, 55, 120 ); else vMaxBounds = Vector( 100, 100, 100 ); if (vBounds.x > vMaxBounds.x || vBounds.y > vMaxBounds.y || vBounds.z > vMaxBounds.z) { char szMessage[256]; sprintf(szMessage,"Server enforces model check and %s is not valid. Your model got these ranges: %.4f,%.4f,%.4f\n",szModelName,vBounds.x, vBounds.y, vBounds.z); AgLog(szMessage); sprintf(szMessage,"Server enforces model check and %s is not valid.\n",szModelName); ConsolePrint(szMessage); #ifdef _DEBUG return true; #else return false; #endif } return true; } bool AgModel::IsChecked() { return m_bFoundAndChecked; } #endif //AG_USE_CHEATPROTECTION //-- Martin Webrant