[Advanced] Hook CPluginHelpersCheck::CreateMessage
-
- Junior Member
- Posts: 4
- Joined: Tue Aug 10, 2021 9:17 am
[Advanced] Hook CPluginHelpersCheck::CreateMessage
Hi,
I'm new to Source Python and, while I haven't developed anything on it yet, I would just like to know if Source.Python provides support for hooking CPluginHelpersCheck::CreateMessage (https://github.com/ValveSoftware/source ... ck.cpp#L25)
Thanks.
I'm new to Source Python and, while I haven't developed anything on it yet, I would just like to know if Source.Python provides support for hooking CPluginHelpersCheck::CreateMessage (https://github.com/ValveSoftware/source ... ck.cpp#L25)
Thanks.
Re: [Advanced] Hook CPluginHelpersCheck::CreateMessage
Yes we do. We also have classes that wrap each of the message types to make it easier to utilize:
http://wiki.sourcepython.com/developing ... e-messages
Look for the messages.Dialog<type> classes in that wiki link.
*Edit: sorry, just realized I misread and you said "hooking" them. Yes, this is definitely possible, as well, but a little more complicated.
http://wiki.sourcepython.com/developing ... e-messages
Look for the messages.Dialog<type> classes in that wiki link.
*Edit: sorry, just realized I misread and you said "hooking" them. Yes, this is definitely possible, as well, but a little more complicated.
- L'In20Cible
- Project Leader
- Posts: 1536
- Joined: Sat Jul 14, 2012 9:29 pm
- Location: Québec
Re: [Advanced] Hook CPluginHelpersCheck::CreateMessage
Untested, but could give you some hints:
Syntax: Select all
# ============================================================================
# >> IMPORTS
# ============================================================================
# Source.Python Imports
# Core
from core import get_interface
# Entities
from entities import Edict
from entities.helpers import index_from_edict
# KeyValues
from keyvalues import KeyValues
# Memory
from memory import Convention
from memory import DataType
from memory import make_object
from memory.hooks import PreHook
# Messages
from messages import DialogType
# Players
from players.entity import Player
# ============================================================================
# >> GLOBALS
# ============================================================================
# Get the plugin helpers check interface
plugin_check = get_interface('server', 'PluginHelpersCheck001')
# ============================================================================
# >> HOOKS
# ============================================================================
# virtual bool CreateMessage( const char *plugin, edict_t *pEntity,
# DIALOG_TYPE type, KeyValues *data );
@PreHook(plugin_check.make_virtual_function(
0,
Convention.THISCALL,
(
DataType.POINTER, DataType.STRING,
DataType.POINTER, DataType.INT, DataType.POINTER
),
DataType.BOOL
))
def pre_create_message(stack_data):
"""Pre hook around IPluginHelpersCheck::CreateMessage."""
plugin = stack_data[1]
player = Player(index_from_edict(make_object(Edict, stack_data[2])))
type_ = DialogType(stack_data[3])
data = make_object(KeyValues, stack_data[4])
-
- Junior Member
- Posts: 4
- Joined: Tue Aug 10, 2021 9:17 am
Re: [Advanced] Hook CPluginHelpersCheck::CreateMessage
Thank you for the instant help, guys. Nice that the addon supports these things directly from user-level scripts, as I doubted since SM doesn't support these from scripts, for example (only through C++ extensions).
I've properly installed Source.Py in my server and started to code first bits around this hook for what I want to achieve, thanks to @L'In20Cible sample. However, I'm getting the following error when the interface load executes:
How to solve it? For info, the server app is HL2:DM
UPDATE: This works instead:
Isn't SP able to translate 'server' or even 'server_srv' to the relative mod's binary path? Similar thing happens when trying to get the engine iface (only 'engine_srv.so' works, note I don't have to prefix any bin directory to it as SP seems to already include the base bin directory in its own search path, or whatever) - May this be considerable an issue to correct/enhance at the SP core?
Another issue, by the way, from my temporary current relevant code:
Produces:
I tried to replace the line by the following, according from what I could understand from the API:
But this error happens instead:
I'd appreciate your help, I want to learn this advanced stuff regardless of my final goal. Thank you.
I've properly installed Source.Py in my server and started to code first bits around this hook for what I want to achieve, thanks to @L'In20Cible sample. However, I'm getting the following error when the interface load executes:
Code: Select all
pluginHelpers = get_interface('server', 'PluginHelpersCheck001')
ValueError: Unable to load library 'server'
How to solve it? For info, the server app is HL2:DM
UPDATE: This works instead:
Code: Select all
pluginHelpers = get_interface('hl2mp/bin/server_srv.so', 'PluginHelpersCheck001')
Isn't SP able to translate 'server' or even 'server_srv' to the relative mod's binary path? Similar thing happens when trying to get the engine iface (only 'engine_srv.so' works, note I don't have to prefix any bin directory to it as SP seems to already include the base bin directory in its own search path, or whatever) - May this be considerable an issue to correct/enhance at the SP core?
Another issue, by the way, from my temporary current relevant code:
Code: Select all
pluginHelpers = get_interface('hl2mp/bin/server_srv.so', 'PluginHelpersCheck001')
createMessageFn = pluginHelpers.make_virtual_function(0, Convention.THISCALL,
# this, plugin, player edict, dialog type, data (KeyValues)
(DataType.POINTER, DataType.STRING, DataType.POINTER, DataType.INT, DataType.POINTER), DataType.BOOL)
@PreHook(createMessageFn)
def pre_create_message(args):
edict = edict_from_pointer(args[2])
player = Player(index_from_edict(edict))
type = DialogType(args[3])
print("Sending dialog of type = ", type)
Produces:
Code: Select all
[SP] Caught an Exception:
Traceback (most recent call last):
File "../addons/source-python/plugins/pluginmessages_helper/pluginmessages_helper.py", line 16, in pre_create_message
player = Player(index_from_edict(args[2]))
Boost.Python.ArgumentError: Python argument types in
_entities._helpers.index_from_edict(Pointer)
did not match C++ signature:
index_from_edict(edict_t* Edict)
I tried to replace the line by the following, according from what I could understand from the API:
Code: Select all
edict = edict_from_pointer(args[2])
player = Player(index_from_edict(edict))
But this error happens instead:
Code: Select all
[SP] Caught an Exception:
Traceback (most recent call last):
File "../addons/source-python/plugins/pluginmessages_helper/pluginmessages_helper.py", line 16, in pre_create_message
edict = edict_from_pointer(args[2])
ValueError: Conversion from "Pointer" (<_memory.Pointer object at 0xea7e61d0>) to "Edict" failed.
I'd appreciate your help, I want to learn this advanced stuff regardless of my final goal. Thank you.
- L'In20Cible
- Project Leader
- Posts: 1536
- Joined: Sat Jul 14, 2012 9:29 pm
- Location: Québec
Re: [Advanced] Hook CPluginHelpersCheck::CreateMessage
adrianilloo wrote:Produces:Code: Select all
[SP] Caught an Exception:
Traceback (most recent call last):
File "../addons/source-python/plugins/pluginmessages_helper/pluginmessages_helper.py", line 16, in pre_create_message
player = Player(index_from_edict(args[2]))
Boost.Python.ArgumentError: Python argument types in
_entities._helpers.index_from_edict(Pointer)
did not match C++ signature:
index_from_edict(edict_t* Edict)
My bad, forgot to cast the pointer in that sample. Basically, since args[2] is the pointer of an Edict, it have to be casted as such first:
Syntax: Select all
from entities import Edict
player = Player(index_from_edict(make_object(Edict, args[2])))
Using index_from_pointer would have worked if args[2] was a CBaseEntity pointer.adrianilloo wrote:I tried to replace the line by the following, according from what I could understand from the API:
But this error happens instead:
ValueError: Conversion from "Pointer" (<_memory.Pointer object at 0xea7e61d0>) to "Edict" failed.[/code]
I'd appreciate your help, I want to learn this advanced stuff regardless of my final goal. Thank you.
-
- Junior Member
- Posts: 4
- Joined: Tue Aug 10, 2021 9:17 am
Re: [Advanced] Hook CPluginHelpersCheck::CreateMessage
L'In20Cible wrote:My bad, forgot to cast the pointer in that sample. Basically, since args[2] is the pointer of an Edict, it have to be casted as such first:Syntax: Select all
from entities import Edict
player = Player(index_from_edict(make_object(Edict, args[2])))
Alright, thank you. Now my script looks like this (making a basic print that shows hook correctness):
Syntax: Select all
from core import get_interface
from entities import Edict
from entities.helpers import index_from_edict
from memory import Convention, DataType, make_object
from memory.hooks import PreHook
from players.entity import Player
pluginHelpers = get_interface('hl2mp/bin/server_srv.so', 'PluginHelpersCheck001')
# pluginHelpers = get_interface('server', 'PluginHelpersCheck001')
createMessageFn = pluginHelpers.make_virtual_function(0, Convention.THISCALL,
# this, plugin, player edict, dialog type, data (KeyValues)
(DataType.POINTER, DataType.STRING, DataType.POINTER, DataType.INT, DataType.POINTER), DataType.BOOL)
@PreHook(createMessageFn)
def OnCreateMessage(args):
edict = make_object(Edict, args[2])
player = Player(index_from_edict(edict))
print("Sending dialog of type {} to player #{}...".format(args[3], player.userid))
However, what about this original approach which failed?
Syntax: Select all
# pluginHelpers = get_interface('server', 'PluginHelpersCheck001')
While this function is the convenient wrapper to get Source virtual object interfaces, it seems to lack smart path search, unlike
Syntax: Select all
FindBinary
Syntax: Select all
server = find_binary('server')
Syntax: Select all
BinaryFile
Syntax: Select all
get_interface
- L'In20Cible
- Project Leader
- Posts: 1536
- Joined: Sat Jul 14, 2012 9:29 pm
- Location: Québec
Re: [Advanced] Hook CPluginHelpersCheck::CreateMessage
No idea. As previously stated, I haven't tested and only wrote an example to provide some hints.adrianilloo wrote:Does it work to you?
adrianilloo wrote:While this function is the convenient wrapper to get Source virtual object interfaces, it seems to lack smart path search, unlikedoes. In this sense, executingSyntax: Select all
FindBinaryinstead works, but then there seems to be no way to connect the resultingSyntax: Select all
server = find_binary('server')object toSyntax: Select all
BinaryFile(e.g. by getting the real translated path and passing it). Isn't there a clear support lack? Or how to make this properly without having to specify the hardcoded 'hl2mp/bin/server_srv.so' path, and naturally, not accessing symbols/signatures manually through the find_binary + operator [] way?Syntax: Select all
get_interface
We could probably add path finding support to get_interface, or even add BinaryFile.get_interface method that resolve the interface from that object. Feel free to open a feature request and/or make a PR on github. However, for now, you could simply format the path yourself with something like that:
Syntax: Select all
from core import GAME_NAME
from core import PLATFORM
pluginHelpers = get_interface(
f'{GAME_NAME}/bin/server{"_srv.so" if PLATFORM == "linux" else ".dll"}',
'PluginHelpersCheck001'
)
Return to “Plugin Development Support”
Who is online
Users browsing this forum: No registered users and 54 guests