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

restructuring: use the wrapper functions instead of call the interface or found functions directly #484

Open
SmileyAG opened this issue Jan 7, 2024 · 2 comments

Comments

@SmileyAG
Copy link
Collaborator

SmileyAG commented Jan 7, 2024

In older versions of the engine, these functions may simply not exist, and therefore if for example you try to call the GetViewAngles function from the cl_enginefunc_t interface in engine versions before the 1.1.0.0 update, then a game crash is the best outcome that can await us

Or in the case of calling a functions directly, they may simply not exist in other versions, and therefore your code will either simply not function as it should or crash the game

Therefore, it required to create wrappers for each function that you are going to use in order to maintain compatibility between all versions of games!

Example of a concept of how it should look:

// In the header

/*
	Set the 'interface_preserved' variable to 'false' only if the interface is completely different from what is presented in our headers and you are not going to modify it
	If only a few functions got added/removed in the middle of interface, then this can be fixed as one of the option by using preprocessor directives (#ifdef, #elif, #ifndef, #if) and releasing a separate build for that version, then it wouldn't require to change that variable
*/
bool interface_preserved = true;
void ClientDLL::GetViewAngles(float *va)
{
	auto &hw = HwDLL::GetInstance();
	if (hw.ORIG_hudGetViewAngles) // If we already found this function by pattern, then cool, let's use it first
	{
		hw.ORIG_hudGetViewAngles(va);
	}
	else if (interface_preserved && pEngfuncs && !hw.is_hlsdk_10) // Okay, we didn't find the function by pattern, but we have access to the interface, so let's use it then!
	{
		pEngfuncs->GetViewAngles(va);
	}
	else if (hw.viewangles) // If the function was still not found, then we ourselves will implement the same logic by reverse-engineering
	{
		va[0] = hw.viewangles->x;
		va[1] = hw.viewangles->y;
		va[2] = hw.viewangles->z;
	}
}
@YaLTeR
Copy link
Owner

YaLTeR commented Jan 8, 2024

If the function is simple enough to be reimplemented manually then do we ever need to call the original? I guess it can be the case that the original fn is found but the required variables aren't, idk

@SmileyAG
Copy link
Collaborator Author

SmileyAG commented Jul 29, 2024

If the function is simple enough to be reimplemented manually then do we ever need to call the original? I guess it can be the case that the original fn is found but the required variables aren't, idk

The priority should only be in the following order (from highest to lowest):

  • Original function (if it is already declared and used in the project, i.e. if function is already hooked to execute custom code before the original function)
  • Interface function (cl_enginefunc_t, enginefuncs_t, engine_studio_api_t, engine_api_t)
  • Custom implementation (and only if it is really required, i.e. if there is no such function in the binary at all, so as not to waste extra time for: searching patterns/offsets, declaring and reverse-engineering the code)

I explain simply and reasonably why it is so: if interface is different and the code couldn't detect it, but the function has already been found, then priority will be given to it.
And this is unlikely to be a false positive, simply because I am going to make each pattern longer for the sake of fewer false positives.

Although, considering the scale of the project, if your version of the game really has different interfaces and the code does not provide support for your binary, then most likely you will crash in any case, simply because in half of the cases the original function is not declared as unnecessary (i.e. we do not want to hook it or search for any global variables or other functions through patterns and offsets from it), for example, we just want to call it and nothing more, and for this it will be enough to call from the interface, so as I say again, we don't need to waste extra time for searching pattern.

@SmileyAG SmileyAG changed the title Use the wrapper functions instead of call the interface or found functions directly restructuring: use the wrapper functions instead of call the interface or found functions directly Jul 29, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants