jbmod-props/props/plugin.cpp
2020-02-25 05:13:39 +02:00

473 lines
No EOL
11 KiB
C++

#define GAME_DLL
#include "plugin.h"
#include "cbase.h"
#include "engine/iserverplugin.h"
#include "toolframework/itoolentity.h"
#include "filesystem.h"
#include "eiface.h"
#include "mathlib.h"
#include "tier1.h"
#include "strtools.h"
#include "datacache/imdlcache.h"
#include "util.h"
#include "props.h"
#include "filter.h"
#define MIN(a,b) (((a)<(b))?(a):(b))
typedef struct {
CUtlSymbol name;
int iGroup;
Vector hull_min;
Vector hull_max;
} prop_t;
class CPluginProps : public IServerPluginCallbacks
{
public:
virtual bool Load(CreateInterfaceFn,CreateInterfaceFn);
virtual void Unload();
virtual void Pause(){}
virtual void UnPause(){}
virtual const char* GetPluginDescription(){
return "Props";
}
virtual void LevelInit(const char*){}
virtual void ServerActivate(edict_t*,int,int){}
virtual void GameFrame(bool){}
virtual void LevelShutdown(){}
virtual void ClientActive(edict_t*);
virtual void ClientDisconnect(edict_t*){}
virtual void ClientPutInServer(edict_t*,const char*){}
virtual void SetCommandClient(int iIndex){
m_iCommandIndex = iIndex;
}
virtual void ClientSettingsChanged(edict_t*){}
virtual PLUGIN_RESULT ClientConnect(bool*,edict_t*,const char*,
const char*,char*,int){return PLUGIN_CONTINUE;}
virtual PLUGIN_RESULT ClientCommand(edict_t*);
virtual PLUGIN_RESULT NetworkIDValidated(const char*,const char*){
return PLUGIN_CONTINUE;
}
int AddGroup(const char* pName);
void GetProps(CUtlVector<int>& props,int iGroup);
void LoadModel(const char* pFolder,const char* pName);
int FindModel(const char* pName);
void SpawnProp(Vector vPos,prop_t& pr);
PLUGIN_RESULT ShowPropMenu(edict_t* pPly,int group,int index);
int m_iCommandIndex;
CUtlVector<CUtlSymbol> m_Groups;
CUtlVector<prop_t> m_Props;
} g_PluginProps;
EXPOSE_SINGLE_INTERFACE_GLOBALVAR(CPluginProps,IServerPluginCallbacks,
INTERFACEVERSION_ISERVERPLUGINCALLBACKS,g_PluginProps);
IVEngineServer* engine = NULL;
IEngineTrace* enginetrace = NULL;
IServerPluginHelpers* helpers = NULL;
IFileSystem* filesystem = NULL;
IMDLCache* mdlcache = NULL;
SetAllowPrecache_t pSAP = NULL;
DispatchSpawn_t pDP = NULL;
CreateEntityByName_t pCEBN = NULL;
bool* pAllowPrecache;
bool CPluginProps::Load(CreateInterfaceFn interfaces,CreateInterfaceFn game)
{
char szLine[MAX_PATH] = {0};
char szPath[MAX_PATH] = {0};
char* pFst;
ConnectTier1Libraries(&interfaces,1);
MathLib_Init(2.2f,2.2f,0.0f,2.0f);
if(!(engine = (IVEngineServer*)interfaces(INTERFACEVERSION_VENGINESERVER,0))
|| !(enginetrace = (IEngineTrace*)interfaces(INTERFACEVERSION_ENGINETRACE_SERVER,0))
|| !(helpers = (IServerPluginHelpers*)interfaces(INTERFACEVERSION_ISERVERPLUGINHELPERS,0))
|| !(filesystem = (IFileSystem*)interfaces(FILESYSTEM_INTERFACE_VERSION,0))
|| !(mdlcache = (IMDLCache*)interfaces(MDLCACHE_INTERFACE_VERSION,0)))
{
Warning("Failed to load due interface mismatch!\n");
return false;
}
if(!(pFst = (char*)SigScan("server.dll",SAP_SIG,SAP_MASK)))
{
Warning("Failed to find sig SAP!\n");
return false;
}
pSAP = (SetAllowPrecache_t)JMP2PTR(pFst);
pAllowPrecache = *(bool**)((char*)pSAP+0x05);
if(!(pDP = (DispatchSpawn_t)SigScan("server.dll",DP_SIG,DP_MASK)))
{
Warning("Failed to find sig DP!\n");
return false;
}
if(!(pCEBN = (CreateEntityByName_t)SigScan("server.dll",CEBN_SIG,CEBN_MASK)))
{
Warning("Failed to find sig CEBN!\n");
return false;
}
KeyValues* pProps = new KeyValues("Props");
if(!(pProps->LoadFromFile(filesystem,"addons/props.txt","GAME")))
{
Warning("File addons/props.txt not found!\n");
return false;
}
KeyValues* pV = pProps->GetFirstSubKey();
do {
KeyValues* pK = pV->GetFirstValue();
do {
LoadModel(pV->GetName(),pK->GetString());
} while((pK=pK->GetNextValue()));
} while((pV=pV->GetNextKey()));
pProps->deleteThis();
return true;
}
int CPluginProps::AddGroup(const char* pName)
{
int index = -1;
for(int i = 0; i < m_Groups.Count(); i++)
{
if(FStrEq(m_Groups[i].String(),pName))
{
index = i;
break;
}
}
if(index == -1)
index = m_Groups.AddToTail(CUtlSymbol(pName));
return index;
}
void CPluginProps::GetProps(CUtlVector<int>& props,int iGroup)
{
for(int i = 0; i < m_Props.Count(); i++)
{
if(m_Props[i].iGroup == iGroup)
props.AddToTail(i);
}
}
void CPluginProps::LoadModel(const char* pFolder,const char* pName)
{
char szBuf[MAX_PATH] = {0};
char szBuf2[MAX_PATH] = {0};
prop_t prop;
strcpy_s(szBuf2,pName);
V_strcpy(szBuf,"models/");
strcat_s(szBuf,szBuf2);
if(!filesystem->FileExists(szBuf,"GAME"))
{
Warning("Model %s doesn't exists!\n");
return;
}
MDLCACHE_CRITICAL_SECTION();
MDLHandle_t mdl = mdlcache->FindMDL(szBuf);
if(mdl == MDLHANDLE_INVALID)
{
Warning("Model %s not found!\n",szBuf);
return;
}
studiohdr_t* pHdr = mdlcache->GetStudioHdr(mdl);
if(!pHdr)
{
Warning("Model %s doesn't have vphysics!\n");
return;
}
/* Add group */
prop.name = CUtlSymbol(szBuf2);
prop.iGroup = AddGroup(pFolder);
prop.hull_min = pHdr->hull_min;
prop.hull_max = pHdr->hull_max;
m_Props.AddToTail(prop);
}
void CPluginProps::Unload()
{
DisconnectTier1Libraries();
}
void CPluginProps::ClientActive(edict_t* pPly)
{
/*
KeyValues *kv = new KeyValues( "msg" );
kv->SetString( "title", "Hello" );
kv->SetString( "msg", "Hello there" );
kv->SetColor( "color", Color( 255, 0, 0, 255 ));
kv->SetInt( "level", 5);
kv->SetInt( "time", 10);
helpers->CreateMessage( pEntity, DIALOG_MSG, kv, this );
kv->deleteThis();
*/
}
inline QAngle* GetEntityEyes(CBaseEntity* pEnt)
{
QAngle* pRet;
__asm
{
push ecx
push edx
mov ecx,[pEnt]
mov edx,[ecx]
call dword ptr [edx+0x1A8]
mov [pRet],eax
pop edx
pop ecx
}
return pRet;
}
inline void GetEyePosition(CBaseEntity* pEnt,Vector* vOut)
{
__asm
{
push ecx
push edx
push [vOut]
mov ecx,[pEnt]
mov edx,[ecx]
call dword ptr [edx+0x1A4]
pop edx
pop ecx
}
}
inline PLUGIN_RESULT CPluginProps::ShowPropMenu(edict_t* pPly,int group,int index)
{
const int iSize = 9;
const int mSize = 7;
char szBuf[MAX_PATH];
CUtlVector<int> props;
KeyValues* msg = new KeyValues("menu");
GetProps(props,group);
msg->SetString("title","Prop menu");
msg->SetString("msg","Prop menu");
msg->SetInt("level",5);
msg->SetInt("time",9999);
msg->SetColor("color",Color(255,255,0,255));
for(int i = index; i < MIN(index+mSize,props.Count()); i++)
{
if(!props.IsValidIndex(i) || !m_Props.IsValidIndex(props[i]))
continue;
prop_t& pr = m_Props[props[i]];
Q_snprintf(szBuf,MAX_PATH,"%d",i-index+1);
KeyValues* sub = msg->FindKey(szBuf,true);
char* pPtr = strchr((char*)pr.name.String(),'/');
if(!pPtr) continue;
pPtr++;
sub->SetString("msg",pPtr);
Q_snprintf(szBuf,MAX_PATH,"prop_spawn %s %s %d",
pr.name.String(),engine->Cmd_Argv(1),index);
sub->SetString("command",szBuf);
}
if(props.Count()-index>=mSize)
{
KeyValues* next = msg->FindKey("8",true);
next->SetString("msg","Next");
Q_snprintf(szBuf,MAX_PATH,"prop_spawnmenu2 %s %d",
engine->Cmd_Argv(1),index+mSize);
next->SetString("command",szBuf);
}
if(index)
{
KeyValues* back = msg->FindKey("9",true);
back->SetString("msg","Back");
Q_snprintf(szBuf,MAX_PATH,"prop_spawnmenu2 %s %d",
engine->Cmd_Argv(1),index-mSize);
back->SetString("command",szBuf);
}
helpers->CreateMessage(pPly,DIALOG_MENU,msg,this);
msg->deleteThis();
return PLUGIN_STOP;
}
PLUGIN_RESULT CPluginProps::ClientCommand(edict_t* pPly)
{
const char* pCmd = engine->Cmd_Argv(0);
const int iSize = 9;
const int mSize = 7;
char szBuf[MAX_PATH];
if(FStrEq(pCmd,"prop_spawn"))
{
if(engine->Cmd_Argc()<2)
return PLUGIN_CONTINUE;
CBaseEntity* pPlayer = pPly->
GetIServerEntity()->GetBaseEntity();
if(!pPlayer) return PLUGIN_CONTINUE;
int iProp = FindModel(engine->Cmd_Argv(1));
if(iProp == -1) return PLUGIN_STOP;
prop_t& pr = m_Props[iProp];
Ray_t ray;
trace_t tr;
Vector vForward,vEye;
QAngle* pAng = GetEntityEyes(pPlayer);
AngleVectors(*pAng,&vForward);
GetEyePosition(pPlayer,&vEye);
CLocalTraceFilter filter(pPlayer);
ray.Init(vEye,vEye+(vForward*MAX_TRACE_LENGTH),pr.hull_min,pr.hull_max);
enginetrace->TraceRay(ray,MASK_SOLID,&filter,&tr);
if(tr.fraction != 1.0)
SpawnProp(tr.endpos,pr);
if(engine->Cmd_Argc() == 4)
{
ShowPropMenu(pPly,atoi(engine->Cmd_Argv(2)),
atoi(engine->Cmd_Argv(3)));
}
return PLUGIN_STOP;
}
else if(FStrEq(pCmd,"prop_spawnmenu"))
{
int index = 0;
if(engine->Cmd_Argc() == 2)
index = atoi(engine->Cmd_Argv(1));
KeyValues* msg;
msg = new KeyValues("menu");
msg->SetString("title","Spawn menu");
msg->SetString("msg","Spawn menu");
msg->SetInt("level",4);
msg->SetInt("time",9999);
msg->SetColor("color",Color(255,255,0,255));
for(int i = index; i < MIN((index+mSize),m_Groups.Count()); i++)
{
Q_snprintf(szBuf,MAX_PATH,"%d",i-index+1);
KeyValues* pVal = msg->FindKey(szBuf,true);
pVal->SetString("msg",m_Groups[i].String());
Q_snprintf(szBuf,MAX_PATH,"prop_spawnmenu2 %d",i);
pVal->SetString("command",szBuf);
}
if((m_Groups.Count()-index)>=mSize)
{
KeyValues* next = msg->FindKey("8",true);
Q_snprintf(szBuf,MAX_PATH,"prop_spawnmenu %d",index+mSize);
next->SetString("msg","Next");
next->SetString("command",szBuf);
}
if(index)
{
KeyValues* back = msg->FindKey("9",true);
Q_snprintf(szBuf,MAX_PATH,"prop_spawnmenu %d",index-mSize);
back->SetString("msg","Back");
back->SetString("command",szBuf);
}
helpers->CreateMessage(pPly,DIALOG_MENU,msg,this);
msg->deleteThis();
return PLUGIN_STOP;
}
else if(FStrEq(pCmd,"prop_spawnmenu2"))
{
if(engine->Cmd_Argc()<2)
return PLUGIN_CONTINUE;
if(engine->Cmd_Argc()==2)
return ShowPropMenu(pPly,atoi(engine->Cmd_Argv(1)),0);
if(engine->Cmd_Argc()>2)
{
return ShowPropMenu(pPly,atoi(engine->Cmd_Argv(1)),
atoi(engine->Cmd_Argv(2)));
}
return PLUGIN_STOP;
}
return PLUGIN_CONTINUE;
}
int CPluginProps::FindModel(const char* pName)
{
for(int i = 0; i < m_Props.Count(); i++)
{
if(FStrEq(m_Props[i].name.String(),pName))
return i;
}
return -1;
}
void EntityKeyValue(CBaseEntity* pEnt,
const char* pKey,const char* pValue)
{
__asm
{
push ecx
push edx
push [pValue]
push [pKey]
mov ecx,[pEnt]
mov edx,[ecx]
call dword ptr [edx+0x78]
pop edx
pop ecx
}
}
void CPluginProps::SpawnProp(Vector vPos,prop_t& pr)
{
char szBuf[MAX_PATH];
CPhysicsProp* pProp;
bool bPrecace = *pAllowPrecache;
*pAllowPrecache = true;
pProp = (CPhysicsProp*)pCEBN("prop_physics",-1);
if(pProp)
{
//%.10f %.10f %.10f
Q_snprintf(szBuf,sizeof(szBuf),"%.10f %.10f %.10f",vPos.x,vPos.y,vPos.z);
EntityKeyValue(pProp,"origin",szBuf);
Q_snprintf(szBuf,sizeof(szBuf),"%.10f %.10f %.10f",0.0f,0.0f,0.0f);
EntityKeyValue(pProp,"angles",szBuf);
szBuf[0] = '\0';
strcpy(szBuf,"models/");
strcat_s(szBuf,pr.name.String());
EntityKeyValue(pProp, "model", szBuf );
EntityKeyValue(pProp, "solid","6");
EntityKeyValue(pProp, "fademindist","-1");
EntityKeyValue(pProp, "fademaxdist","0");
EntityKeyValue(pProp, "fadescale","1");
EntityKeyValue(pProp, "inertiaScale","1.0");
EntityKeyValue(pProp, "physdamagescale","0.1");
pProp->Precache();
pDP(pProp);
pProp->Activate();
}
*pAllowPrecache = false;
}