Raised This Month: $32 Target: $400
 8% 

[FRAMEWORK] CEntity


Post New Thread Reply   
 
Thread Tools Display Modes
Nimgoble
Junior Member
Join Date: Apr 2006
Old 10-15-2012 , 23:58   Re: [FRAMEWORK] CEntity
Reply With Quote #41

Will this framework work with HL2DM? It seems that the source is geared more towards TF2.
Nimgoble is offline
asherkin
SourceMod Developer
Join Date: Aug 2009
Location: OnGameFrame()
Old 10-16-2012 , 04:44   Re: [FRAMEWORK] CEntity
Reply With Quote #42

Quote:
Originally Posted by Nimgoble View Post
Will this framework work with HL2DM? It seems that the source is geared more towards TF2.
The basis of it will, you'd need to strip out all the TF2 specific parts from CPlayer mainly.
__________________
asherkin is offline
Nimgoble
Junior Member
Join Date: Apr 2006
Old 10-16-2012 , 07:47   Re: [FRAMEWORK] CEntity
Reply With Quote #43

Quote:
Originally Posted by asherkin View Post
The basis of it will, you'd need to strip out all the TF2 specific parts from CPlayer mainly.
Would that not be a good thing to incorporate in to the framework, itself? Have CPlayer encompass JUST the CBasePlayer functionality and have something like "CTF2Player" derive off of that, implementing the TF2-specific behavior?
Nimgoble is offline
asherkin
SourceMod Developer
Join Date: Aug 2009
Location: OnGameFrame()
Old 10-16-2012 , 08:34   Re: [FRAMEWORK] CEntity
Reply With Quote #44

Quote:
Originally Posted by Nimgoble View Post
Would that not be a good thing to incorporate in to the framework, itself? Have CPlayer encompass JUST the CBasePlayer functionality and have something like "CTF2Player" derive off of that, implementing the TF2-specific behavior?
I'm gonna take a guess and say you didn't read the TODO list in the first post.
__________________
asherkin is offline
Nimgoble
Junior Member
Join Date: Apr 2006
Old 10-16-2012 , 09:58   Re: [FRAMEWORK] CEntity
Reply With Quote #45

Quote:
Originally Posted by asherkin View Post
I'm gonna take a guess and say you didn't read the TODO list in the first post.
...

Quote:
Support mods other than TF2 (CPlayer should only contain CBasePlayer sdk stuff and create optional CTFPlayer/CCSPlayer derives)
Well, that's embarrassing... Lol.

Also, are there any plans to make a version of CEntity that doesn't require SourceMod? So, those of us that are using MM:S and don't want to make the change(for whatever reason) can use it.

Last edited by Nimgoble; 10-16-2012 at 10:03.
Nimgoble is offline
kadet.89
Veteran Member
Join Date: Nov 2012
Location: Serbia
Old 08-30-2014 , 05:16   Re: [FRAMEWORK] CEntity
Reply With Quote #46

CEntity.h:

PHP Code:
    ...
    
virtual const QAngleEyeAngles (); 
    
virtual const QAngleLocalEyeAngles ();
    
virtual const VectorGetViewOffset ();
    
virtual Vector GetStepOrigin ();
    
virtual QAngle GetStepAngles ();
    ...
    
DECLARE_DEFAULTHEADER(EyeAngles,  const QAngle& ,  ());
    
DECLARE_DEFAULTHEADER(LocalEyeAngles,  const QAngle& ,  ());
    
DECLARE_DEFAULTHEADER(GetViewOffset,  const Vector& ,  ());
    
DECLARE_DEFAULTHEADER(GetStepOrigin,  Vector,  ());
    
DECLARE_DEFAULTHEADER(GetStepAngles,  QAngle,  ());
    ... 
CEntity.cpp:

PHP Code:
    SH_DECL_MANUALHOOK0(EyeAngles000, const QAngle&);
    
SH_DECL_MANUALHOOK0(LocalEyeAngles000, const QAngle&);
    
SH_DECL_MANUALHOOK0(GetViewOffset000, const Vector&);
    
SH_DECL_MANUALHOOK0(GetStepOrigin000Vector);
    
SH_DECL_MANUALHOOK0(GetStepAngles000QAngle);
    ...
    
DECLARE_HOOK(EyeAnglesCEntity);
    
DECLARE_HOOK(LocalEyeAnglesCEntity);
    
DECLARE_HOOK(GetViewOffsetCEntity);
    
DECLARE_HOOK(GetStepOriginCEntity);
    
DECLARE_HOOK(GetStepAnglesCEntity);
    ...
    
DECLARE_DEFAULTHANDLER(CEntity,     EyeAngles,    const QAngle&, (), ());     //line 569
    
DECLARE_DEFAULTHANDLER(CEntity,     LocalEyeAngles,    const QAngle&, (), ());     //line 570
    
DECLARE_DEFAULTHANDLER(CEntity,     GetViewOffset,    const Vector&, (), ()); 
    
DECLARE_DEFAULTHANDLER(CEntity,     GetStepOrigin,    Vector, (), ());     
    
DECLARE_DEFAULTHANDLER(CEntity,     GetStepAngles,    QAngle, (), ());  //line 605 

Error:
centity.cpp(569): error C2101: '&' on constant
centity.cpp(570): error C2101: '&' on constant
centity.cpp(605): error C2440: 'type cast' : cannot convert from "int" to "QAngle"

What is wrong with QAngle? If I replace QAngle with Vector, there is no error.
kadet.89 is offline
Send a message via Skype™ to kadet.89
StaX36
Junior Member
Join Date: Aug 2011
Old 02-17-2015 , 10:56   Re: [FRAMEWORK] CEntity
Reply With Quote #47

Hey while using this framework I ran into a couple of problems/bugs I want to list here and how I fixed them.

First inputs can't access member variables of the custom entity class.

PHP Code:
void CMyCustomEnt::Input(inputdata_t &inputdata){
    
Msg("I am at %X = %i\n", &m_iNomm_iNom);

Since the engine uses the CBaseEntity pointer to call the function the offset of m_iNom is added to the wrong pointer.

This can be fixed if we implement our own "input execution loop". For this I changed:

PHP Code:
#undef DEFINE_INPUTFUNC
#define DEFINE_INPUTFUNC( fieldtype, inputname, inputfunc ) { fieldtype, #inputfunc, { 0, 0 }, 1, FTYPEDESC_INPUT, inputname, NULL, (inputfunc_t)(&classNameTypedef::inputfunc) } 
form CEntity.h line 105 to:

PHP Code:
typedef void (CEntity::*inputfunc_centity_t)(inputdata_t &data);
#undef DEFINE_INPUTFUNC
#define DEFINE_INPUTFUNC( fieldtype, inputname, inputfunc ) { fieldtype, #inputfunc, { NULL, NULL }, 1, FTYPEDESC_INPUT, inputname, NULL, (inputfunc_t)static_cast <inputfunc_centity_t> (&classNameTypedef::inputfunc) } 
Next I had to change CEntity::GetDataDescMap() form CEntity.cpp line 99 into:

PHP Code:
datamap_tCEntity::GetDataDescMap()
{
    
datamap_tbase NULL;
    if (!
m_bInGetDataDescMap)
    {
         
base SH_MCALL(BaseEntity(), GetDataDescMap)();
         
m_DataMap.baseMap base;
         return &
m_DataMap;
    }
        

    
SET_META_RESULT(MRES_IGNORED);
    
SH_GLOB_SHPTR->DoRecall();
    
SourceHook::EmptyClass *thisptr reinterpret_cast<SourceHook::EmptyClass*>(SH_GLOB_SHPTR->GetIfacePtr());
    
base = (thisptr->*(__SoureceHook_FHM_GetRecallMFPGetDataDescMap(thisptr)))();
    
m_DataMap.baseMap base;
    
RETURN_META_VALUE(MRES_SUPERCEDE, &m_DataMap);

Now I copied some variant_t functions form the engine which will be used for the loop:
From game/server/cbase.cpp line 1303 I copied variant_t::Convert( fieldtype_t newType ). In this function line 1438 to 1449 had to be changed to:

PHP Code:
case FIELD_EHANDLE:
{
    
// convert the string to an entity by locating it by classname << But the engine uses FindEntityByName
    
CEntity *ent NULL;
    if (
iszVal != NULL_STRING)
    {
        
// FIXME: do we need to pass an activator in here?
        
CEntity *pEnt;
        for (
int i 0<= MAX_EDICTSi++)
        {
            
pEnt CEntity::Instance(i);
            if (!
pEnt)
            {
                continue;
            }

            
char name[128];
            if (
strcmp(namepEnt->GetTargetName()) == 0)
            {
                
ent pEnt;
            }
        }
    }
    
SetEntity(ent->BaseEntity());
    return 
true;

From game/server/cbase.cpp line 1269 I copied variant_t::SetOther( void *data )
From game/server/variant_t.cpp line 13 I copied variant_t::SetEntity( CBaseEntity *val )
All the functions need to be paste to util.cpp, I also had to define:

PHP Code:
CBaseEntityList g_pEntityList
which isn't used in these functions but it caused a linker error for me when its not there.

In the last step I copied the "input execution loop" in CBaseEntity::AcceptInput(...) from game/server/baseentity.cpp line 3885 to 3965.
And pasted it in CEntity.cpp CEntity::AcceptInput before line 541 !!!

The function had to be modified so it uses the CEntity pointer and not the CBaseEntity one!
Important parts are:

PHP Code:
inputfunc_centity_t pfnInput = (inputfunc_centity_t)dmap->dataDesc[i].inputFunc
and

PHP Code:
if (strcmp(dmap->dataClassName"CEntity") == 0)
    break; 
So that we jump back to the the engine one...

PHP Code:
bool CEntity::AcceptInput(const char *szInputNameCEntity *pActivatorCEntity *pCallervariant_t Valueint outputID)
{

for (
datamap_t *dmap GetDataDescMap(); dmap != NULLdmap dmap->baseMap)
    {


        
// search through all the actions in the data description, looking for a match
        
for (int i 0dmap->dataNumFieldsi++)
        {
            if (
dmap->dataDesc[i].flags FTYPEDESC_INPUT)
            {
                if (!
Q_stricmp(dmap->dataDesc[i].externalNameszInputName))
                {
                    
// found a match
                    // convert the value if necessary
                    
if (Value.FieldType() != dmap->dataDesc[i].fieldType)
                    {
                        if (!(
Value.FieldType() == FIELD_VOID && dmap->dataDesc[i].fieldType == FIELD_STRING)) // allow empty strings
                        
{
                            if (!
Value.Convert((fieldtype_t)dmap->dataDesc[i].fieldType))
                            {
                                
// bad conversion
                                
Warning("!! ERROR: bad input/output link:\n!! %s(%s,%s) doesn't match type from %s(%s)\n",
                                    
GetClassname(), GetClassname(), szInputName,
                                    (
pCaller != NULL) ? pCaller->GetClassname() : "<null>",
                                    (
pCaller != NULL) ? pCaller->GetTargetName() : "<null>");
                                return 
false;
                            }
                        }
                    }
                    
// call the input handler, or if there is none just set the value
                    
inputfunc_centity_t pfnInput = (inputfunc_centity_t)dmap->dataDesc[i].inputFunc;

                    if (
pfnInput)
                    {
                        
// Package the data into a struct for passing to the input handler.
                        
inputdata_t data;
                        
data.pActivator pActivator->BaseEntity();
                        
data.pCaller pCaller->BaseEntity();
                        
data.value Value;
                        
data.nOutputID outputID;

                        (
this->*pfnInput)(data);
                    }
                    else if (
dmap->dataDesc[i].flags FTYPEDESC_KEY)
                    {
                        
// set the value directly
                        
Value.SetOther(((char*)this) + dmap->dataDesc[i].fieldOffset[TD_OFFSET_NORMAL]);

                        
// TODO: if this becomes evil and causes too many full entity updates, then we should make
                        // a macro like this:
                        //
                        // define MAKE_INPUTVAR(x) void Note##x##Modified() { x.GetForModify(); }
                        //
                        // Then the datadesc points at that function and we call it here. The only pain is to add
                        // that function for all the DEFINE_INPUT calls.
                        //NetworkStateChanged(); //Comment this out!
                    
}

                    return 
true;
                }

            }

        }
        if (
strcmp(dmap->dataClassName"CEntity") == 0)
            break;
    }

if (!
m_bInAcceptInput)
    {
        return 
SH_MCALL(BaseEntity(), AcceptInput)(szInputName, *pActivator, *pCallerValueoutputID);
    }
    
/**
    * This gets the award for the worst hack so far. Detects the end of waiting for players and probably lots of other things.
    * Forces players out of vehicles.
.... and so on ..... 
Now with these changes you can also easily implement custom keyvalues: Hook CBaseEntity::KeyValue(const char*, const char*) and get the function ParseKeyvalue from game/server/saverestore_gamedll.cpp you also need to copy some UTIL_ functions...
Then in CEntity::KeyValue add these before if(!m_bInKeyValue):

PHP Code:
    for (datamap_t *dmap GetDataDescMap(); dmap != NULLdmap dmap->baseMap)
    {
        if (
ParseKeyvalue(thisdmap->dataDescdmap->dataNumFieldsszKeyNameszValue))
        {
            return 
true;
        }
        if (
strcmp(dmap->dataClassName"CEntity") == 0)
            break;
    } 
The last bug(problem) I ran into is that when I used ent_create <mycustomentity> the custom classname isn't correctly applied.
The problem is that the string pasted to ent_create is freed after the execution of it and the classname is set at the end of CEntityManager::Create with exactly the pointer to this string...
I fixed it by using the PooledString system like this:

PHP Code:
void CEntity::SetClassname(const char *pClassName)
{
    
string_t newName AllocPooledString(pClassName);
    
m_iClassname newName;



Last edited by StaX36; 02-17-2015 at 11:00.
StaX36 is offline
StaX36
Junior Member
Join Date: Aug 2011
Old 04-09-2015 , 15:57   Re: [FRAMEWORK] CEntity
Reply With Quote #48

I also noticed that when you override an entity DataDesc e.g. to add new inputs or outputs to an existing entity all standard IO gets removed. The problem can be fixed if we pass our DataDesc from the CEntity BaseClass to the baseMap variable.

So DO NOT use the definition of BEGIN_DATADESC from the SDK use this definition instead:

PHP Code:
#define BEGIN_DATADESC_CENTITY( className ) \
datamap_t className::m_DataMap = { 00#className, NULL }; \
datamap_t *className::GetDataDescMap(void) { \
    
m_DataMap.baseMap BaseClass::GetDataDescMap(); \
    return &
m_DataMap; \
} \
datamap_t *className::GetBaseMap() { datamap_t *pResultDataMapAccess((BaseClass *)NULL, &pResult); return pResult; } \
BEGIN_DATADESC_GUTS(className
StaX36 is offline
Reply



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT -4. The time now is 14:18.


Powered by vBulletin®
Copyright ©2000 - 2024, vBulletin Solutions, Inc.
Theme made by Freecode