diff --git a/cl_dll/cdll_int.cpp b/cl_dll/cdll_int.cpp index 9c008e5..5ac540a 100644 --- a/cl_dll/cdll_int.cpp +++ b/cl_dll/cdll_int.cpp @@ -38,6 +38,8 @@ #include "tri.h" #include "vgui_TeamFortressViewport.h" #include "../public/interface.h" +#include "physics.h" +#include"phy_corpse.h" cl_enginefunc_t gEngfuncs; CHud gHUD; @@ -154,6 +156,7 @@ int DLLEXPORT Initialize( cl_enginefunc_t *pEnginefuncs, int iVersion ) } +bool newLevelBegin = false; /* ========================== HUD_VidInit @@ -170,9 +173,30 @@ int DLLEXPORT HUD_VidInit( void ) gHUD.VidInit(); VGui_Startup(); + newLevelBegin = true; return 1; } +void CheckLevelChange() +{ + if (newLevelBegin) + { + newLevelBegin = false; + + const char* pLevelName = gEngfuncs.pfnGetLevelName(); + if (pLevelName && pLevelName[0]) { + gPhysics.ChangeLevel(pLevelName); + if (!pgCorpseMgr) + delete pgCorpseMgr; + pgCorpseMgr = new CorpseManager(); + } + else + { + gEngfuncs.pfnClientCmd("disconnect\n"); + gEngfuncs.Con_Printf("Couldn't get map name from level name!\n"); + } + } +} /* ========================== diff --git a/cl_dll/entity.cpp b/cl_dll/entity.cpp index 32d23aa..6d0a909 100644 --- a/cl_dll/entity.cpp +++ b/cl_dll/entity.cpp @@ -16,6 +16,8 @@ #include "Exports.h" #include "particleman.h" +#include"physics.h" +#include extern IParticleMan *g_pParticleMan; void Game_AddObjects( void ); @@ -61,6 +63,15 @@ int DLLEXPORT HUD_AddEntity( int type, struct cl_entity_s *ent, const char *mode } + if (ent->index && ent->index < 512) + { + // server side brush entity only.(breakables, trains, func_walls...) + if (ent->model->type == modtype_t::mod_brush) + { + gPhysics.AddCollider(ent); + } + } + return 1; } @@ -318,6 +329,12 @@ void DLLEXPORT HUD_CreateEntities( void ) Game_AddObjects(); GetClientVoiceMgr()->CreateEntities(); + + static float oldtime = 0; + float currentTime = gEngfuncs.GetClientTime(); + float delta = currentTime-oldtime; + oldtime = currentTime; + gPhysics.Update(delta); } #if defined( _TFC ) @@ -470,6 +487,9 @@ void DLLEXPORT HUD_TempEntUpdate ( } if ( !active ) // Kill it { + if (pTemp->callback && pTemp->flags & FTENT_KILLCALLBACK) + pTemp->callback(pTemp, frametime, client_time); + pTemp->next = *ppTempEntFree; *ppTempEntFree = pTemp; if ( !pprev ) // Deleting at head of list diff --git a/cl_dll/gsphysics/phy_corpse.h b/cl_dll/gsphysics/phy_corpse.h new file mode 100644 index 0000000..e3130c6 --- /dev/null +++ b/cl_dll/gsphysics/phy_corpse.h @@ -0,0 +1,41 @@ +#pragma once + +#include +#include +#include + +// magic num +#define PhyCorpseFlag1 (753951) +#define PhyCorpseFlag2 (152358) + +#define MAX_ENTITIES 512 + + +class CorpseManager +{ +public: + CorpseManager(void); + + // check if the entity is already dead + bool IsEntityDead(cl_entity_t* ent); + + // tells the mgr that the entity died just now. + void EntityDie(cl_entity_t* ent); + + // if entity plays any sequences other than death sequences, + // we tells the mgr this entity is alive. + void EntityRespawn(cl_entity_t* ent); + + // create ragdoll corpse for specified entity + TEMPENTITY* CreateRagdollCorpse(cl_entity_t* ent); + + // check if the entity is a ragdoll corpse (temp entity) + bool IsRagdollCorpse(cl_entity_t* ent); + +private: + // max server side entity count elements + bool _entityDead[MAX_ENTITIES]; + int _corpseIndex = MAX_ENTITIES; +}; + +extern CorpseManager* pgCorpseMgr; \ No newline at end of file diff --git a/cl_dll/gsphysics/physics.cpp b/cl_dll/gsphysics/physics.cpp new file mode 100644 index 0000000..722f72f --- /dev/null +++ b/cl_dll/gsphysics/physics.cpp @@ -0,0 +1,124 @@ + +#include +#include +#include +#include +//#include + +#pragma comment(lib, "mscoree.lib") + +PhsicsAPI gPhysics; + +#ifdef _DEBUG +const wchar_t PhyDllPath[] = L".\\gsphysics\\bin\\GoldsrcPhysics.dll"; +#else// _DEBUG +const wchar_t PhyDllPath[] = L".\\gsphysics\\bin\\GoldsrcPhysics.dll"; +#endif + +//globle CLR handle +ICLRMetaHost* pMetaHost = nullptr; +ICLRMetaHostPolicy* pMetaHostPolicy = nullptr; +ICLRRuntimeHost* pRuntimeHost = nullptr; +ICLRRuntimeInfo* pRuntimeInfo = nullptr; + +void ReleaseCLR() +{ + if (pRuntimeInfo != nullptr) + { + pRuntimeInfo->Release(); + pRuntimeInfo = nullptr; + } + + if (pRuntimeHost != nullptr) + { + pRuntimeHost->Release(); + pRuntimeHost = nullptr; + } + + if (pMetaHost != nullptr) + { + pMetaHost->Release(); + pMetaHost = nullptr; + } +} + +int InitCLR() +{ + if (pRuntimeInfo != nullptr) + return 0; + HRESULT hr = CLRCreateInstance(CLSID_CLRMetaHost, IID_ICLRMetaHost, (LPVOID*)&pMetaHost); + hr = pMetaHost->GetRuntime(L"v4.0.30319", IID_PPV_ARGS(&pRuntimeInfo)); + + if (FAILED(hr)) { + ReleaseCLR(); + } + + hr = pRuntimeInfo->GetInterface(CLSID_CLRRuntimeHost, IID_PPV_ARGS(&pRuntimeHost)); + hr = pRuntimeHost->Start(); + return (int)hr; +} + +int ExitCLR() +{ + pRuntimeHost->Stop();//return HRESULT + ReleaseCLR(); + return 0; +} + +void* GetFunctionPointer(LPWSTR name) +{ + void* pfn = NULL; + + const int bufsize = 128; + wchar_t buffer[bufsize];//marshal args to [0xXXXX|MethodName] format + swprintf(buffer, bufsize, L"%p|%s", &pfn, name); + + DWORD dwRet = 0; + HRESULT hr = pRuntimeHost->ExecuteInDefaultAppDomain(PhyDllPath, + L"UsrSoft.ManagedExport.ManagedExporter", + L"GetFunctionPointer", + buffer, + &dwRet); + + if (hr != S_OK) + exit(12345); + if ((DWORD)pfn != dwRet) + exit(54321); + + return pfn; +} + +//auto generated +extern "C" void InitPhysicsInterface(char* msg) +{ + InitCLR(); + gPhysics.Set = (void(_stdcall*)(const char* key, const char* value))GetFunctionPointer(L"GoldsrcPhysics.ExportAPIs.PhysicsMain.Set"); + gPhysics.Test = (void(_stdcall*)())GetFunctionPointer(L"GoldsrcPhysics.ExportAPIs.PhysicsMain.Test"); + gPhysics.InitSystem = (void(_stdcall*)(const char* modFolder, void* pEngineStudioAPI))GetFunctionPointer(L"GoldsrcPhysics.ExportAPIs.PhysicsMain.InitSystem"); + gPhysics.ChangeLevel = (void(_stdcall*)(const char* mapName))GetFunctionPointer(L"GoldsrcPhysics.ExportAPIs.PhysicsMain.ChangeLevel"); + gPhysics.LevelReset = (void(_stdcall*)())GetFunctionPointer(L"GoldsrcPhysics.ExportAPIs.PhysicsMain.LevelReset"); + gPhysics.Update = (void(_stdcall*)(float delta))GetFunctionPointer(L"GoldsrcPhysics.ExportAPIs.PhysicsMain.Update"); + gPhysics.Pause = (void(_stdcall*)())GetFunctionPointer(L"GoldsrcPhysics.ExportAPIs.PhysicsMain.Pause"); + gPhysics.Resume = (void(_stdcall*)())GetFunctionPointer(L"GoldsrcPhysics.ExportAPIs.PhysicsMain.Resume"); + gPhysics.ShotDown = (void(_stdcall*)())GetFunctionPointer(L"GoldsrcPhysics.ExportAPIs.PhysicsMain.ShotDown"); + gPhysics.ShowConfigForm = (void(_stdcall*)())GetFunctionPointer(L"GoldsrcPhysics.ExportAPIs.PhysicsMain.ShowConfigForm"); + gPhysics.CreateRagdollController = (void(_stdcall*)(int entityId, char* modelName))GetFunctionPointer(L"GoldsrcPhysics.ExportAPIs.PhysicsMain.CreateRagdollController"); + gPhysics.CreateRagdollControllerIndex = (void(_stdcall*)(int entityId, int index))GetFunctionPointer(L"GoldsrcPhysics.ExportAPIs.PhysicsMain.CreateRagdollControllerIndex"); + gPhysics.CreateRagdollControllerModel = (void(_stdcall*)(int entityId, void * model))GetFunctionPointer(L"GoldsrcPhysics.ExportAPIs.PhysicsMain.CreateRagdollControllerModel"); + gPhysics.StartRagdoll = (void(_stdcall*)(int entityId))GetFunctionPointer(L"GoldsrcPhysics.ExportAPIs.PhysicsMain.StartRagdoll"); + gPhysics.StopRagdoll = (void(_stdcall*)(int entityId))GetFunctionPointer(L"GoldsrcPhysics.ExportAPIs.PhysicsMain.StopRagdoll"); + gPhysics.SetupBonesPhysically = (void(_stdcall*)(int entityId))GetFunctionPointer(L"GoldsrcPhysics.ExportAPIs.PhysicsMain.SetupBonesPhysically"); + gPhysics.ChangeOwner = (void(_stdcall*)(int oldEntity, int newEntity))GetFunctionPointer(L"GoldsrcPhysics.ExportAPIs.PhysicsMain.ChangeOwner"); + gPhysics.SetVelocity = (void(_stdcall*)(int entityId, Vector3 * v))GetFunctionPointer(L"GoldsrcPhysics.ExportAPIs.PhysicsMain.SetVelocity"); + gPhysics.DisposeRagdollController = (void(_stdcall*)(int entityId))GetFunctionPointer(L"GoldsrcPhysics.ExportAPIs.PhysicsMain.DisposeRagdollController"); + gPhysics.ImpulseBone = (void(_stdcall*)(int entityId, int boneId, Vector3 * force))GetFunctionPointer(L"GoldsrcPhysics.ExportAPIs.PhysicsMain.ImpulseBone"); + gPhysics.ClearRagdoll = (void(_stdcall*)())GetFunctionPointer(L"GoldsrcPhysics.ExportAPIs.PhysicsMain.ClearRagdoll"); + gPhysics.HeadShootRagdoll = (void(_stdcall*)(int entityId, Vector3 * force))GetFunctionPointer(L"GoldsrcPhysics.ExportAPIs.PhysicsMain.HeadShootRagdoll"); + gPhysics.Explosion = (void(_stdcall*)(Vector3 * pos, float intensity))GetFunctionPointer(L"GoldsrcPhysics.ExportAPIs.PhysicsMain.Explosion"); + gPhysics.Shoot = (void(_stdcall*)(Vector3 * from, Vector3 * force))GetFunctionPointer(L"GoldsrcPhysics.ExportAPIs.PhysicsMain.Shoot"); + gPhysics.PickBodyLocal = (void(_stdcall*)(Vector3 from, Vector3 to))GetFunctionPointer(L"GoldsrcPhysics.ExportAPIs.PhysicsMain.PickBodyLocal"); + gPhysics.ReleaseBodyLocal = (void(_stdcall*)())GetFunctionPointer(L"GoldsrcPhysics.ExportAPIs.PhysicsMain.ReleaseBodyLocal"); + gPhysics.MoveBodyLocal = (void(_stdcall*)(Vector3 from, Vector3 to))GetFunctionPointer(L"GoldsrcPhysics.ExportAPIs.PhysicsMain.MoveBodyLocal"); + gPhysics.SetPose = (void(_stdcall*)(int entityId, float* pBoneWorldTransform))GetFunctionPointer(L"GoldsrcPhysics.ExportAPIs.PhysicsMain.SetPose"); + gPhysics.AddCollider = (void(_stdcall*)(void*))GetFunctionPointer(L"GoldsrcPhysics.ExportAPIs.PhysicsMain.AddCollider"); +} \ No newline at end of file diff --git a/cl_dll/gsphysics/physics.h b/cl_dll/gsphysics/physics.h new file mode 100644 index 0000000..7ca3645 --- /dev/null +++ b/cl_dll/gsphysics/physics.h @@ -0,0 +1,180 @@ + + +#pragma once + +typedef struct +{ + float x, y, z; +}Vector3; + + + +typedef struct PhsicsAPI_s +{ + /* + + */ + void(_stdcall* Set)(const char* key, const char* value); + + /* + + */ + void(_stdcall* Test)(); + + /* + + */ + void(_stdcall* InitSystem)(const char* modFolder, void* pEngineStudioAPI); + + /* + + Load map geomitry collider. + + */ + void(_stdcall* ChangeLevel)(const char* mapName); + + /* + + 地图不变,内容重置,清理在游戏中动态创建的各种CollisionObjects + cs的每一局结束可以调用 + + */ + void(_stdcall* LevelReset)(); + + /* + + Physics world update + + */ + void(_stdcall* Update)(float delta); + + /* + + */ + void(_stdcall* Pause)(); + + /* + + */ + void(_stdcall* Resume)(); + + /* + + Close physics system and release physics resources. + + */ + void(_stdcall* ShotDown)(); + + /* + + Show configration form. + Using cvar to call this is recommended. + + */ + void(_stdcall* ShowConfigForm)(); + + /* + + */ + void(_stdcall* CreateRagdollController)(int entityId, char* modelName); + + /* + + */ + void(_stdcall* CreateRagdollControllerIndex)(int entityId, int index); + + /* + model_t* model + */ + void(_stdcall* CreateRagdollControllerModel)(int entityId, void* model); + + /* + + */ + void(_stdcall* StartRagdoll)(int entityId); + + /* + + */ + void(_stdcall* StopRagdoll)(int entityId); + + /* + + */ + void(_stdcall* SetupBonesPhysically)(int entityId); + + /* + + */ + void(_stdcall* ChangeOwner)(int oldEntity, int newEntity); + + /* + + */ + void(_stdcall* SetVelocity)(int entityId, Vector3* v); + + /* + + */ + void(_stdcall* DisposeRagdollController)(int entityId); + + /* + + */ + void(_stdcall* ImpulseBone)(int entityId, int boneId, Vector3* force); + + /* + + */ + void(_stdcall* ClearRagdoll)(); + + /* + + */ + void(_stdcall* HeadShootRagdoll)(int entityId, Vector3* force); + + /* + + Set an explosion on the specified position. + The impact range is calculated automatically via intensity. + + */ + void(_stdcall* Explosion)(Vector3* pos, float intensity); + + /* + + Shoot an invisable bullet to apply impulse to the rigidbody it hits. + eye pos.contains direction and intensity. + */ + void(_stdcall* Shoot)(Vector3* from, Vector3* force); + + /* + Eye pos or camera originCamera origin + direction + */ + void(_stdcall* PickBodyLocal)(Vector3 from, Vector3 to); + + /* + + Release picked body + + */ + void(_stdcall* ReleaseBodyLocal)(); + + /* + Eye pos or camera originCamera origin + direction + */ + void(_stdcall* MoveBodyLocal)(Vector3 from, Vector3 to); + + void(_stdcall*SetPose)(int entityId, float* pBoneWorldTransform); + + void(_stdcall* AddCollider)(void* pEntity); + +}PhsicsAPI; + + +// Containts all the physics system API +// Call [InitPhysicsInterface] before using these API +extern PhsicsAPI gPhysics; + +// Call this function to initialize [gPhysics]. +extern "C" void InitPhysicsInterface(char* msg); \ No newline at end of file diff --git a/cl_dll/in_camera.cpp b/cl_dll/in_camera.cpp index 755d85d..5e508ea 100644 --- a/cl_dll/in_camera.cpp +++ b/cl_dll/in_camera.cpp @@ -149,10 +149,11 @@ typedef struct } moveclip_t; extern trace_t SV_ClipMoveToEntity (edict_t *ent, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end); - +void CheckLevelChange(); void DLLEXPORT CAM_Think( void ) { // RecClCamThink(); + CheckLevelChange(); vec3_t origin; vec3_t ext, pnt, camForward, camRight, camUp; diff --git a/common/r_efx.h b/common/r_efx.h index 1763894..2a10b4a 100644 --- a/common/r_efx.h +++ b/common/r_efx.h @@ -84,7 +84,7 @@ color24 gTracerColors[] = #define FTENT_SPARKSHOWER 0x00020000 #define FTENT_NOMODEL 0x00040000 // Doesn't have a model, never try to draw ( it just triggers other things ) #define FTENT_CLIENTCUSTOM 0x00080000 // Must specify callback. Callback function is responsible for killing tempent and updating fields ( unless other flags specify how to do things ) - +#define FTENT_KILLCALLBACK 0x00100000 // calls the call back when we kill the ent typedef struct tempent_s { int flags; diff --git a/projects/vs2019/PhyStudioModelRenderer.cpp b/projects/vs2019/PhyStudioModelRenderer.cpp new file mode 100644 index 0000000..1644d3e --- /dev/null +++ b/projects/vs2019/PhyStudioModelRenderer.cpp @@ -0,0 +1,328 @@ +//========================================================================== +// +//========================================================================== + +#include +#include "hud.h" +#include "cl_util.h" +#include "const.h" +#include "com_model.h" +#include "studio.h" +#include "entity_state.h" +#include "cl_entity.h" +#include "dlight.h" +#include "triangleapi.h" + +#include +#include +#include +#include + +#include "studio_util.h" +#include "r_studioint.h" + +#include "StudioModelRenderer.h" +#include "PhyStudioModelRenderer.h" +#include +#include "Exports.h" + +#include "phy_corpse.h" +#include"physics.h" + +// +// Override the StudioModelRender virtual member functions here to implement custom bone +// setup, blending, etc. +// + +// Global engine <-> studio model rendering code interface +extern engine_studio_api_t IEngineStudio; + +// The renderer object, created on the stack. +PhyStudioModelRenderer g_StudioRenderer; +/* +==================== +PhyStudioModelRenderer + +==================== +*/ +PhyStudioModelRenderer::PhyStudioModelRenderer(void) +{ +} +void PhyStudioModelRenderer::Init(void) +{ + CStudioModelRenderer::Init(); + InitPhysicsInterface(NULL); + gPhysics.InitSystem("valve", &IEngineStudio); +} +int PhyStudioModelRenderer::StudioDrawRagdoll(int flags) +{ + alight_t lighting; + vec3_t dir; + + m_pCurrentEntity = IEngineStudio.GetCurrentEntity(); + IEngineStudio.GetTimes(&m_nFrameCount, &m_clTime, &m_clOldTime); + IEngineStudio.GetViewInfo(m_vRenderOrigin, m_vUp, m_vRight, m_vNormal); + IEngineStudio.GetAliasScale(&m_fSoftwareXScale, &m_fSoftwareYScale); + + m_pRenderModel = m_pCurrentEntity->model; + m_pStudioHeader = (studiohdr_t*)IEngineStudio.Mod_Extradata(m_pRenderModel); + IEngineStudio.StudioSetHeader(m_pStudioHeader); + IEngineStudio.SetRenderModel(m_pRenderModel); + + StudioSetUpTransform(0); + + if (flags & STUDIO_RENDER) + { + // see if the bounding box lets us trivially reject, also sets + if (!IEngineStudio.StudioCheckBBox()) + return 0; + + (*m_pModelsDrawn)++; + (*m_pStudioModelCount)++; // render data cache cookie + + if (m_pStudioHeader->numbodyparts == 0) + return 1; + } + + if (m_pCurrentEntity->curstate.movetype == MOVETYPE_FOLLOW) + { + StudioMergeBones(m_pRenderModel); + } + else + { + gPhysics.SetupBonesPhysically(m_pCurrentEntity->index); + m_pCurrentEntity->origin.x = (*m_pbonetransform)[1][0][3]; + m_pCurrentEntity->origin.y = (*m_pbonetransform)[1][1][3]; + m_pCurrentEntity->origin.z = (*m_pbonetransform)[1][2][3]; + } + StudioSaveBones(); + + if (flags & STUDIO_EVENTS) + { + StudioCalcAttachments(); + IEngineStudio.StudioClientEvents(); + // copy attachments into global entity array + if (m_pCurrentEntity->index > 0) + { + cl_entity_t* ent = gEngfuncs.GetEntityByIndex(m_pCurrentEntity->index); + + memcpy(ent->attachment, m_pCurrentEntity->attachment, sizeof(vec3_t) * 4); + } + } + + if (flags & STUDIO_RENDER) + { + lighting.plightvec = dir; + IEngineStudio.StudioDynamicLight(m_pCurrentEntity, &lighting); + + IEngineStudio.StudioEntityLight(&lighting); + + // model and frame independant + IEngineStudio.StudioSetupLighting(&lighting); + + // get remap colors + + m_nTopColor = m_pCurrentEntity->curstate.colormap & 0xFF; + m_nBottomColor = (m_pCurrentEntity->curstate.colormap & 0xFF00) >> 8; + + IEngineStudio.StudioSetRemapColors(m_nTopColor, m_nBottomColor); + + StudioRenderModel(); + } + + return 1; +} + +int PhyStudioModelRenderer::StudioDrawModel(int flags) +{ + m_pCurrentEntity = IEngineStudio.GetCurrentEntity(); + + if (pgCorpseMgr->IsRagdollCorpse(m_pCurrentEntity)) + return StudioDrawRagdoll(flags); + + if (m_pCurrentEntity->index)// pass worldspawn or tempentity + + // hard coded here, we need a better way. + if ((31 <= m_pCurrentEntity->curstate.sequence && + m_pCurrentEntity->curstate.sequence <= 43 && + strstr(m_pCurrentEntity->model->name, "scientist")) || + (15 <= m_pCurrentEntity->curstate.sequence && + m_pCurrentEntity->curstate.sequence <= 19 && + strstr(m_pCurrentEntity->model->name, "zombie"))) + { + // If the entity (ie players, NPCs) is alive. + if (!pgCorpseMgr->IsEntityDead(m_pCurrentEntity)) + { + // let studio setup bone matrix, so we can use it as ragdoll init pose. + CStudioModelRenderer::StudioDrawModel(0); + + TEMPENTITY* tempent = pgCorpseMgr->CreateRagdollCorpse(m_pCurrentEntity); + // Set init ragdoll pose + gPhysics.SetPose(tempent->entity.index, (float*)m_pbonetransform); + pgCorpseMgr->EntityDie(m_pCurrentEntity); + } + else + { + // Simply return. Do not render the original entity. + // Because it has already dead, a ragdoll replace it. + return 0; + } + } + else + { + pgCorpseMgr->EntityRespawn(m_pCurrentEntity); + } + + // normal render + return CStudioModelRenderer::StudioDrawModel(flags); +} + +int PhyStudioModelRenderer::StudioDrawPlayer(int flags, entity_state_s* pplayer) +{ + return CStudioModelRenderer::StudioDrawPlayer(flags, pplayer); +} + +//////////////////////////////////// +// Hooks to class implementation +//////////////////////////////////// + +/* +==================== +R_StudioDrawPlayer + +==================== +*/ +int R_StudioDrawPlayer(int flags, entity_state_t* pplayer) +{ + return g_StudioRenderer.StudioDrawPlayer(flags, pplayer); +} + +/* +==================== +R_StudioDrawModel + +==================== +*/ +int R_StudioDrawModel(int flags) +{ + return g_StudioRenderer.StudioDrawModel(flags); +} + +/* +==================== +R_StudioInit + +==================== +*/ +void R_StudioInit(void) +{ + g_StudioRenderer.Init(); +} + +// The simple drawing interface we'll pass back to the engine +r_studio_interface_t studio = +{ + STUDIO_INTERFACE_VERSION, + R_StudioDrawModel, + R_StudioDrawPlayer, +}; + +/* +==================== +HUD_GetStudioModelInterface + +Export this function for the engine to use the studio renderer class to render objects. +==================== +*/ +int DLLEXPORT HUD_GetStudioModelInterface(int version, struct r_studio_interface_s** ppinterface, struct engine_studio_api_s* pstudio) +{ + // RecClStudioInterface(version, ppinterface, pstudio); + + if (version != STUDIO_INTERFACE_VERSION) + return 0; + + // Point the engine to our callbacks + *ppinterface = &studio; + + // Copy in engine helper functions + memcpy(&IEngineStudio, pstudio, sizeof(IEngineStudio)); + + // Initialize local variables, etc. + R_StudioInit(); + + // Success + return 1; +} + +#pragma region phy_corpse.cpp +bool gMapExistTempEnt = 0; +CorpseManager* pgCorpseMgr = nullptr; + +CorpseManager::CorpseManager(void) +{ + memset(_entityDead, 0, MAX_ENTITIES); +} + +bool CorpseManager::IsEntityDead(cl_entity_t* ent) +{ + return _entityDead[ent->index]; +} + +void CorpseManager::EntityDie(cl_entity_t* ent) +{ + _entityDead[ent->index] = true; +} + +void CorpseManager::EntityRespawn(cl_entity_t* ent) +{ + _entityDead[ent->index] = false; +} +void OnRagdollKill(struct tempent_s* ent, float frametime, float currenttime) +{ + gPhysics.DisposeRagdollController(ent->entity.index); + gEngfuncs.Con_DPrintf("free ragdoll [%d]\n", ent->entity.index); +} +TEMPENTITY* CorpseManager::CreateRagdollCorpse(cl_entity_t* ent) +{ + TEMPENTITY* tempent = gEngfuncs.pEfxAPI->CL_TempEntAlloc(ent->curstate.origin, ent->model); + tempent->entity.curstate.iuser1 = ent->index; + tempent->entity.curstate.iuser3 = PhyCorpseFlag1; + tempent->entity.curstate.iuser4 = PhyCorpseFlag2; + tempent->entity.curstate.body = ent->curstate.body; + tempent->entity.curstate.skin = ent->curstate.skin; + entity_state_t* entstate = &ent->curstate; + entity_state_t* tempstate = &tempent->entity.curstate; + tempent->entity.angles = ent->angles; + tempent->entity.latched = ent->latched; + tempstate->angles = entstate->angles; + tempstate->animtime = entstate->animtime; + tempstate->sequence = entstate->sequence; + tempstate->aiment = entstate->aiment; + tempstate->frame = entstate->frame; + + + tempent->die = gEngfuncs.GetClientTime() + 30; + tempent->flags = FTENT_KILLCALLBACK; + tempent->callback = OnRagdollKill; + tempent->entity.index = _corpseIndex++; + gPhysics.CreateRagdollControllerModel(tempent->entity.index, (ent->model)); + gPhysics.StartRagdoll(tempent->entity.index); + gPhysics.SetVelocity(tempent->entity.index, (Vector3*)&ent->curstate.velocity); + + cl_entity_t* local = gEngfuncs.GetLocalPlayer(); + Vector v = (ent->origin - local->origin).Normalize(); + v = v * 5; + gPhysics.SetVelocity(tempent->entity.index, (Vector3*)&v); + + gEngfuncs.Con_DPrintf("corpse [%d]'s velocity is %f\n", tempent->entity.index, ent->curstate.velocity.Length()); + gEngfuncs.Con_DPrintf("create corpse [%d] for entity [%d]\n", tempent->entity.index, ent->index); + return tempent; +} + +bool CorpseManager::IsRagdollCorpse(cl_entity_t* ent) +{ + return (ent->curstate.iuser3 == PhyCorpseFlag1 && + ent->curstate.iuser4 == PhyCorpseFlag2); +} +#pragma endregion + diff --git a/projects/vs2019/PhyStudioModelRenderer.h b/projects/vs2019/PhyStudioModelRenderer.h new file mode 100644 index 0000000..9a6c89c --- /dev/null +++ b/projects/vs2019/PhyStudioModelRenderer.h @@ -0,0 +1,28 @@ +// Author: Anchur + +#if !defined( PHYSTUDIOMODELRENDERER_H ) +#define PHYSTUDIOMODELRENDERER_H +#if defined( _WIN32 ) +#pragma once +#endif + +#include +/* +==================== +PhyStudioModelRenderer + +==================== +*/ +class PhyStudioModelRenderer : public CStudioModelRenderer +{ +public: + PhyStudioModelRenderer(void); + // override public interfaces + virtual int StudioDrawModel(int flags); + virtual int StudioDrawPlayer(int flags, struct entity_state_s* pplayer); + + virtual void Init(void); + int StudioDrawRagdoll(int flags); +}; + +#endif // PHYSTUDIOMODELRENDERER_H \ No newline at end of file diff --git a/projects/vs2019/hl_cdll.vcxproj b/projects/vs2019/hl_cdll.vcxproj index b8976ee..e7b144b 100644 --- a/projects/vs2019/hl_cdll.vcxproj +++ b/projects/vs2019/hl_cdll.vcxproj @@ -20,7 +20,7 @@ DynamicLibrary true - NotSet + MultiByte v142 @@ -60,7 +60,7 @@ Disabled WIN32;_CRT_SECURE_NO_WARNINGS;_DEBUG;_WINDOWS;CLIENT_DLL;CLIENT_WEAPONS;HL_DLL;%(PreprocessorDefinitions) MultiThreadedDebug - ..\..\dlls;..\..\cl_dll;..\..\public;..\..\common;..\..\pm_shared;..\..\engine;..\..\utils\vgui\include;..\..\game_shared;..\..\external;%(AdditionalIncludeDirectories) + ..\..\dlls;..\..\cl_dll;..\..\public;..\..\common;..\..\pm_shared;..\..\engine;..\..\utils\vgui\include;..\..\game_shared;..\..\external;..\..\cl_dll\gsphysics;%(AdditionalIncludeDirectories) true /Zc:threadSafeInit- %(AdditionalOptions) @@ -87,7 +87,7 @@ true WIN32;_CRT_SECURE_NO_WARNINGS;NDEBUG;_WINDOWS;CLIENT_DLL;CLIENT_WEAPONS;HL_DLL;%(PreprocessorDefinitions) MultiThreaded - ..\..\dlls;..\..\cl_dll;..\..\public;..\..\common;..\..\pm_shared;..\..\engine;..\..\utils\vgui\include;..\..\game_shared;..\..\external;%(AdditionalIncludeDirectories) + ..\..\dlls;..\..\cl_dll;..\..\public;..\..\common;..\..\pm_shared;..\..\engine;..\..\utils\vgui\include;..\..\game_shared;..\..\external;..\..\cl_dll\gsphysics;%(AdditionalIncludeDirectories) true /Zc:threadSafeInit- %(AdditionalOptions) @@ -120,8 +120,8 @@ - + @@ -190,6 +190,7 @@ + @@ -201,7 +202,8 @@ - + + @@ -233,6 +235,7 @@ + diff --git a/projects/vs2019/hl_cdll.vcxproj.filters b/projects/vs2019/hl_cdll.vcxproj.filters index ec62548..e2a7f7e 100644 --- a/projects/vs2019/hl_cdll.vcxproj.filters +++ b/projects/vs2019/hl_cdll.vcxproj.filters @@ -55,6 +55,12 @@ {bd9d5958-4e67-4bff-bbd8-6ba6dfcdb720} + + {7060eba1-a095-4150-9eed-4958dbc297b1} + + + {fe80d87c-f9dd-4c46-a121-01ee3f029bca} + @@ -153,9 +159,6 @@ Source Files\cl_dll - - Source Files\cl_dll - Source Files\cl_dll @@ -306,6 +309,12 @@ Source Files\pm_shared + + Source Files\cl_dll\gsphysics + + + Source Files\cl_dll\gsphysics + @@ -338,9 +347,6 @@ Header Files\cl_dll - - Header Files\cl_dll - Header Files\cl_dll @@ -431,6 +437,15 @@ Header Files\common + + Header Files\cl_dll\gsphysics + + + Header Files\cl_dll\gsphysics + + + Header Files\cl_dll\gsphysics +