Seems like you found a bug. After some testing, seems like calling an hooked function that return a float or a double through the ST0 register is causing an access violation which causes a crash when the game itself is calling said function. I've tested multiple functions on different games and always got the same results. The shortest reproducible code:
Syntax: Select all
from memory import Convention, DataType, NULL, Pointer
from memory.hooks import PreHook
from players.entity import Player
pl = Player(1)
fn = pl.pointer.make_virtual_function(437, Convention.THISCALL, [DataType.POINTER,], DataType.FLOAT)
print(fn(pl))
@PreHook(fn)
def callback(stack):
print(stack)
print(fn(pl))
Which results into:
Syntax: Select all
190.0
Hooking function: type=PRE, addr=1505250672, conv=THISCALL, args=(_memory.DataType.POINTER,), rtype=FLOAT, callback=<function callback at 0x1EFB6348>
[SP] Caught an Exception:
Traceback (most recent call last):
File "..\addons\source-python\packages\source-python\plugins\command.py", line 162, in load_plugin
plugin = self.manager.load(plugin_name)
File "..\addons\source-python\packages\source-python\plugins\manager.py", line 194, in load
plugin._load()
File "..\addons\source-python\packages\source-python\plugins\instance.py", line 74, in _load
self.module = import_module(self.import_name)
File "..\addons\source-python\plugins\testing\testing.py", line 14, in <module>
print(fn(pl))
File "<string>", line 1, in <lambda>
RuntimeError: Access violation while executing address '0'.
[SP] Plugin 'testing' was unable to be loaded.
Where the first print statement is working as intended and prints 190.0 then the second is causing the access violation. The game itself is not catching the exception, so it simply crashes. It is also not a conflict between dyncall and DynamicHooks because a straight call from a function exported by boost is also causing a crash after being hooked:
Syntax: Select all
from engines.server import engine_server
from memory import get_virtual_function
from memory.hooks import PreHook
print(engine_server.sentence_length(1))
@PreHook(get_virtual_function(engine_server, 'SentenceLength'))
def pre_sentence_lenght(stack_data):
pass
print(engine_server.sentence_length(1))
So yeah, there is definitely an issue somewhere when hooking a function that returns a float or a double. At least, THISCALL functions on Windows.