Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add LookupEntityAttachment & GetEntityAttachment natives #1653

Merged
merged 6 commits into from
Jan 3, 2022

Conversation

Mikusch
Copy link
Contributor

@Mikusch Mikusch commented Nov 26, 2021

#1555

This is a very common SDKCall used in plugins and I think it'd be a great idea to have a native for it.

I agree.

Overview

This PR adds two new natives:

// Same as SDKCall to:  int CBaseAnimating::LookupAttachment(const char *)
native int LookupEntityAttachment(int entity, const char[] name);

// Same as SDKCall to:  bool CBaseAnimating::GetAttachment(int, Vector &, QAngle &)
native bool GetEntityAttachment(int entity, int attachment, float origin[3], float angles[3]);

Example usage:

int attachment = LookupEntityAttachment(client, "head");
if (attachment == 0)
	return;

float origin[3], angles[3];
if (!GetEntityAttachment(client, attachment, origin, angles))
	return;

PrintToServer("Attachment %d at: (%f %f %f)", attachment, origin[0], origin[1], origin[2]);

Gamedata for CS:GO, CS:S, L4D, L4D2 and TF2 is provided, but has not been tested by me.

Implementation

Using the virtual CBaseAnimating::GetAttachment(int, matrix3x4_t &) was a deliberate choice because virtual offsets are generally easier to maintain than signatures. The matrix3x4_t is converted to world position and world angles internally.
Some of the other overloads are also inlined on a few games, making this the best choice.

Since this call can only be used on classes inheriting CBaseAnimating, we check if the DT_BaseAnimating SendTable exists on the entity, throwing a native error if it doesn't.
This safeguard could be greatly improved with a call to CBaseEntity::GetBaseAnimating, but would require more gamedata (maybe something to consider for the future?)

Footnote

I have not been able to test this for any game other than TF2. I'd be grateful if other people could assist with testing
this on different games and engine versions.

This is my first time actively working with C++, so excuse some rookie mistakes.

Copy link
Member

@Headline Headline left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tested for CS:GO Windows, functions properly.

Looks like a great patch, thank you for seeing this through!

Copy link
Member

@KyleSanderson KyleSanderson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice one - thank you for the contribution. Can you add sdk2013 Gamedata outside of the comments? The networkable stuff was a big issue with ents a decade ago.

CBaseEntity* pEntity;
ENTINDEX_TO_CBASEENTITY(params[1], pEntity);

ServerClass* pClass = ((IServerUnknown*)pEntity)->GetNetworkable()->GetServerClass();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This needs a null check on networkable.

Copy link
Member

@Kenzzer Kenzzer Dec 2, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The networkable null check should be unnecessary on this. Or at least amount to no extra security.
IServerUnknown is inherited by IServerEntity which itself is inherited by CBaseEntity, and if we look at the function implementation by valve :

inline IServerNetworkable *CBaseEntity::GetNetworkable()
{
	return &m_Network;
}

And CBaseEntity definition

private:
	// NOTE: Keep this near vtable so it's in cache with vtable.
	CServerNetworkProperty m_Network;

The networkable interface should never be null. And valve also doesn't seem to ever null check this in their code base
https://github.com/ValveSoftware/source-sdk-2013/search?q=GetNetworkable

It's also used under CBaseEntity constructor regardless of whether it's server side only or not, this rules out the possibility of it ever being invalid.

CBaseEntity::CBaseEntity( bool bServerOnly )
{
	// code
	NetworkProp()->Init( this );
	// code
}
inline CServerNetworkProperty *CBaseEntity::NetworkProp()
{
	return &m_Network;
}

https://github.com/ValveSoftware/source-sdk-2013/blob/0d8dceea4310fde5706b3ce1c70609d72a38efdf/mp/src/game/server/baseentity.cpp#L367
https://github.com/ValveSoftware/source-sdk-2013/blob/0d8dceea4310fde5706b3ce1c70609d72a38efdf/mp/src/game/server/baseentity.h#L2378

CBaseEntity* pEntity;
ENTINDEX_TO_CBASEENTITY(params[1], pEntity);

ServerClass* pClass = ((IServerUnknown*)pEntity)->GetNetworkable()->GetServerClass();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto

ServerClass* pClass = ((IServerUnknown*)pEntity)->GetNetworkable()->GetServerClass();
if (!FindNestedDataTable(pClass->m_pTable, "DT_BaseAnimating"))
{
return pContext->ThrowNativeError("Entity %d (%d) is not a CBaseAnimating", gamehelpers->ReferenceToIndex(params[1]), params[1]);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you elaborate what you would like changed here?

ENTINDEX_TO_CBASEENTITY(params[1], pEntity);

ServerClass* pClass = ((IServerUnknown*)pEntity)->GetNetworkable()->GetServerClass();
if (!FindNestedDataTable(pClass->m_pTable, "DT_BaseAnimating"))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@asherkin am I losing it or is this not calling back to the safe nesting datatable code from core?

@Mikusch
Copy link
Contributor Author

Mikusch commented Dec 2, 2021

Can you add sdk2013 Gamedata outside of the comments?

What exactly do you mean by this? There isn't any gamedata that would make sense to add for sdk2013.

Copy link
Member

@asherkin asherkin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This all looks good to me, the error handling and datatable bits all seem fine - one tiny comment on how the API is presented but otherwise I'd say the meat of this is all good to go.

plugins/include/sdktools_functions.inc Outdated Show resolved Hide resolved
Copy link
Member

@asherkin asherkin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

@asherkin
Copy link
Member

@KyleSanderson please could you re-review this or dismiss your stale review.

Mikusch added a commit to Mikusch/source-vehicles that referenced this pull request Dec 23, 2021
Mikusch added a commit to Mikusch/source-vehicles that referenced this pull request Dec 23, 2021
@asherkin asherkin dismissed KyleSanderson’s stale review January 3, 2022 13:11

Concerns addressed, no follow up

@asherkin asherkin merged commit afc9310 into alliedmodders:master Jan 3, 2022
@Mikusch Mikusch deleted the attachment-natives branch January 3, 2022 13:20
Mikusch added a commit to Mikusch/source-vehicles that referenced this pull request Jul 3, 2022
* Update syntax for SourceMod 1.11

* Remove DHooks dependency

* Remove LookupAttachment SDKCall

alliedmodders/sourcemod#1653

* Remove deprecated forwards

* Rename ShowKeyHintText

* Move pragmas up

* A few more updates

* Switch to AddTargetsToMenu2

* Update default admin flags

* Update native return values

* Update code and comment style

* More style changes

* yes

* Change weird vector declaration

* Re-register vehicle on plugin reload

* Rework passenger damage in vehicles

* Enforce convars

* Use EOS constant

* Add semicolons

* Comments

* Don't use nonexistant define

* More headers
@mixern6
Copy link

mixern6 commented Jan 31, 2023

I might have an idea how to get attachment points without using signatures, though can't check if that will work:
Get IMDLCache* from MDLCACHE_INTERFACE_VERSION
That will provide methods to get studiohdr_t*, studiohwdata_t*, vcollide_t*, virtualmodel_t , vertexFileHeader_t by model name.
Providing the structures and the methods are correct, it should be possible to get attachment names this way: studiohdr_t::pAttachment(i).pszName( )

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants