-
-
Notifications
You must be signed in to change notification settings - Fork 433
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
Reconcile the concept of Edict & Networkable across the codebase #1903
Conversation
Rebuilt the changes on an older linux debian (buster), this time everything compiled. I also addressed a dumb logic change I made that would crash servers on map load. |
So compiling Sourcemod with clang-3.8 didn't please a few extensions, that hack themselves into sourcemod. So I moved up to clang-11, still debian buster |
Have you reviewed https://bugs.alliedmods.net/show_bug.cgi?id=5297 (and the child bug?). |
Ty for sharing this. No I hadn't thought of checking this bug tracker. Instead of trusting the edict's networkable ptr, you instead directly go for the CBaseEntity inline const char * CBaseEdict::GetClassName() const
{
if ( !m_pUnk )
return "";
return m_pNetworkable->GetClassName();
} We address the same problem once again. Gamerules natives, retrieve the edict's networkable, but we should be retrieving the serverunknow's(CBaseEntity) networkable. So I addressed that, and I also took the liberty of eliminating all the null checks against networkable interface. As they're artifacts of a bygone time when the interface was instead found through the edict. Edit: @psychonic reviewed this through discord, and wants the null checks kept, in the event a new game ever so slightly deviate from the regular network behavior. So I'll add those checks back as well as adding them where they're missing |
Re-added removed null checks, and added new ones. Changed the error messages in Get/SetProp natives to better reflect reality.
New field test build ?Sorry to the people that wish to field test this. I have no SM builds to provide atm, I'll upload one later today or tomorrow. Null checks updateI've re-added the removed null checks, and I added new ones where they had been previously missing. Examples of where ServerClass is currently null checked on sourcemod/extensions/tf2/criticals.cpp Lines 170 to 175 in 250dc1b
Streamline code further ?I also thought it might be a good idea to overload IGameHelpers::FindServerClass sourcemod/public/IGameHelpers.h Line 102 in 250dc1b
And introduce SeverClass* IGameHelpers::FindServerClass(CBaseEntity*) , so that in the event a mod doesn't have a networkable interface for its entities, we can just create a ifdef SE_GAME in this function to add support. Without having to do that for all the natives in SourceMod that currently do
IServerNetworkable *pNet = pUnk->GetNetworkable();
if (!pNet)
{
return;
}
ServerClass *pClass = pNet->GetServerClass();
if (!pClass)
{
return;
} to ServerClass *pClass = gamehelpers/halflife2->GetServerClass(pUnk/pEntity);
if (!pClass)
{
return;
} The null status of
|
Decided to roll with the idea of overloading In my opinion this does streamline the code much further, and overall improves understandability of the code in certain places. The retrieval of the |
The gamerules fix has been uploaded to my server for a week now, and the crash hasn't re-surfaced. Every other changes are either a merely extra null check, or the use of the new vtable entry of IGameHelpers. I haven't noticed any regression or new bugs following those changes. Attached to this post is a build of the latest commit for those that wish to try it privately (tf2 only). |
public/IGameHelpers.h
Outdated
* | ||
* @return ServerClass pointer on success, nullptr on failure. | ||
*/ | ||
virtual ServerClass *FindServerClass(CBaseEntity *pEntity) = 0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This isn't safe to add like this since it won't actually get added to the end of the vtable. (It will be next to the other overload). An extension compiled against v11 is going to have a bad time if they access this version. At minimum, IsVersionCompatible would need to be overridden to return false
if a lower version is requested. If not wanting to break compatibility, that could be taken one step further to add an additional interface registration with a shim providing the previous version. Another alternative is just using a different name.
I'm not sure how much any of that is worth the addition.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just giving it a different name so it's simple compat seems like the way to go.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That'd be fine, too.
This fixes #1902 and potential crash in other natives.
What is this all about ?
Well, the scope of this PR mainly boils down to
CBaseEdict::GetNetworkable
&IServerUnknown::GetNetworkable
(CBaseEntity::GetNetworkable)The former, is the edict that gives a pointer (that might or might not be valid) of the attached entity's networkable
The latter, is the entity/unknown that gives a pointer (that is always valid) of the attached entity's networkable
What are the benefits ?
The PR is mostly a speculative a fix for PR #1902 but everything points towards an unproperly setup Networkable's vtable. Which is strange, because Sourcemod retrives the networkable interface of any entity in a lot of places.
https://github.com/alliedmodders/sourcemod/search?q=GetNetworkable
But the key difference with all of them, and the gamerules native (as well tf2's objective ressource native, and another function). Is that they use the edict_t ptr, to retrieve the networkable interface. While everywhere else in the codebase, we go from edict ptr to unknown ptr (the cbaseentity) to the networkable interface.
This leads me to believe, the engine doesn't properly clean up the networkable ptr on its edict_t(s) which is assigned by the srcds.
Why is a core file modified ?
The goal is to keep the retrieval of the networkable interface consistent across all the codebase. That includes core files.
Furthermore, this also fixes a non logical message of the Set/GetEntProp natives
Edict %d (%d) is not networkable
Edicts are networkable by definition. We should have never gotten that far to begin with, if we started from an edict. But we don't, we start from a
IServerUnknown
. So we remove this useless check, whose error message never ever showed in sourcemode entire lifetime, I browsed the forums & google never found a post where a plugin maker asks about the error message.# Why is there some null check removed on networkable ?Edited : After discussion, it has been decided null checks should not be removed. Instead null checks have been added where they had been missing.
This should be field tested
I haven't had the chance to try the changes myself. This is all speculative, but I'm confident in the research I've performed.
Attached to this post is a zip file containing the sourcemod installation compiled with the changes of this PR (linux), minus the pgsql extension + spcomp, which gave me troubles to be compiled because of zlib.
sourcemod.zipOUTDATEDsourcemod.zipOUTDATEDsourcemod.zip - Latest