How to reset the player's sound to normal on player_blind?

Please post any questions about developing your plugin here. Please use the search function before posting!
arawra
Senior Member
Posts: 190
Joined: Fri Jun 21, 2013 6:51 am

Postby arawra » Mon Feb 02, 2015 6:46 am

When you're getting a pointer from a virtual function (correct term?) that returns a player, does it return a CCSPlayer object? How do you go about getting a PlayerEntity object out of that?
User avatar
satoon101
Project Leader
Posts: 2697
Joined: Sat Jul 07, 2012 1:59 am

Postby satoon101 » Mon Feb 02, 2015 7:30 am

That specific function returns an entity's (player's) Pointer. To get a BaseEntity/PlayerEntity instance from that, you first need to get the index from the pointer:

Syntax: Select all

from entities.helpers import index_from_pointer
from players.entity import PlayerEntity
from memory.hooks import PreHook

player = PlayerEntity(1)

@PreHook(player.deafen)
def pre_deafen(args):
index = index_from_pointer(args[0])
player = PlayerEntity(index)
Image
User avatar
Mahi
Senior Member
Posts: 236
Joined: Wed Aug 29, 2012 8:39 pm
Location: Finland

Postby Mahi » Mon Feb 02, 2015 12:59 pm

Syntax: Select all

from players.entity import PlayerEntity
from players.helpers import index_from_userid
from events import Event

@Event
def player_spawn(game_event):
entity = PlayerEntity(index_from_userid(game_event.get_int('userid')))
entity.health += 50

[SP] Caught an Exception:
Traceback (most recent call last):
File '..\addons\source-python\packages\source-python\events\listener.py', line
90, in fire_game_event
callback(game_event)
File '..\addons\source-python\plugins\test\test.py', line 8, in player_spawn
entity.health += 50
File '..\addons\source-python\packages\source-python\entities\entity.py', line
83, in __getattr__
raise AttributeError('Attribute '{0}' not found'.format(attr))

AttributeError: Attribute 'health' not found
stonedegg
Senior Member
Posts: 141
Joined: Sun Aug 12, 2012 11:45 am

Postby stonedegg » Tue Feb 03, 2015 7:29 pm

Maybe we can have a soundhook like sourcemod it has: https://github.com/pmrowla/sourcemod-central/blob/master/extensions/sdktools/vsound.cpp

Simple example here: https://forums.alliedmods.net/showthread.php?t=252979

That would be nice
User avatar
Doldol
Senior Member
Posts: 200
Joined: Sat Jul 07, 2012 7:09 pm
Location: Belgium

Postby Doldol » Tue Feb 03, 2015 8:40 pm

stonedegg wrote:Maybe we can have a soundhook like sourcemod it has: https://github.com/pmrowla/sourcemod-central/blob/master/extensions/sdktools/vsound.cpp

Simple example here: https://forums.alliedmods.net/showthread.php?t=252979

That would be nice


You can most likely have this if you can find out which functions the game calls to play a sound and then block or modify them with SP.

But I don't like the idea of adding in easy to use hooks that don't map 1:1 with the engine.
User avatar
L'In20Cible
Project Leader
Posts: 1533
Joined: Sat Jul 14, 2012 9:29 pm
Location: Québec

Postby L'In20Cible » Wed Feb 04, 2015 7:26 am

Doldol wrote:You can most likely have this if you can find out which functions the game calls to play a sound and then block or modify them with SP.

Syntax: Select all

from engines.sound import engine_sound
from filters.recipients import RecipientFilter
from memory import Argument
from memory import Convention
from memory import get_object_pointer
from memory import make_object
from memory import Pointer
from memory import Return
from memory.hooks import PreHook

EMIT_SOUND_FUNC = get_object_pointer(engine_sound).make_virtual_function(4,
Convention.THISCALL, (Argument.POINTER, Argument.POINTER, Argument.INT,
Argument.INT, Argument.STRING, Argument.FLOAT, Argument.FLOAT,
Argument.INT, Argument.INT, Argument.INT, Argument.POINTER,
Argument.POINTER, Argument.POINTER, Argument.BOOL, Argument.FLOAT,
Argument.INT), Return.VOID)

@PreHook(EMIT_SOUND_FUNC)
def post_entity_creation(args):
print(args[4])
While this method gets called, most of the sounds are predicted and played by the clients so blocking it won't really change anything in most cases.
stonedegg
Senior Member
Posts: 141
Joined: Sun Aug 12, 2012 11:45 am

Postby stonedegg » Wed Feb 04, 2015 4:51 pm

L'In20Cible wrote:
Doldol wrote:You can most likely have this if you can find out which functions the game calls to play a sound and then block or modify them with SP.

Syntax: Select all

from engines.sound import engine_sound
from filters.recipients import RecipientFilter
from memory import Argument
from memory import Convention
from memory import get_object_pointer
from memory import make_object
from memory import Pointer
from memory import Return
from memory.hooks import PreHook

EMIT_SOUND_FUNC = get_object_pointer(engine_sound).make_virtual_function(4,
Convention.THISCALL, (Argument.POINTER, Argument.POINTER, Argument.INT,
Argument.INT, Argument.STRING, Argument.FLOAT, Argument.FLOAT,
Argument.INT, Argument.INT, Argument.INT, Argument.POINTER,
Argument.POINTER, Argument.POINTER, Argument.BOOL, Argument.FLOAT,
Argument.INT), Return.VOID)

@PreHook(EMIT_SOUND_FUNC)
def post_entity_creation(args):
print(args[4])
While this method gets called, most of the sounds are predicted and played by the clients so blocking it won't really change anything in most cases.


Nice! Maybe we don't need to block the sounds at all, but just set their volume to 0.0?

Edit: Just tested in csgo, shot some bullets and stuff but nothing was printed (no errors either).
User avatar
Ayuto
Project Leader
Posts: 2195
Joined: Sat Jul 07, 2012 8:17 am
Location: Germany

Postby Ayuto » Wed Feb 04, 2015 7:34 pm

Yes, the code L'In20Cible posted is for CS:S.
User avatar
BackRaw
Senior Member
Posts: 537
Joined: Sun Jul 15, 2012 1:46 am
Location: Germany
Contact:

Postby BackRaw » Wed Feb 04, 2015 10:30 pm

Windows or Linux? I can test it on a CS:S Linux server :)
My Github repositories:

Source.Python: https://github.com/backraw
User avatar
Ayuto
Project Leader
Posts: 2195
Joined: Sat Jul 07, 2012 8:17 am
Location: Germany

Postby Ayuto » Sun Apr 26, 2015 5:48 pm

Ayuto wrote:I have now taken a look at CS:GO and found this signature.

Code: Select all

55 8B EC 83 EC 28 56 57 8B F9 F3 0F 11 4D FC
However, this is a special function as it uses a custom calling convention on Windows. The "this" pointer is passed through the ecx register (that's usual for a Windows thiscall), but the other argument is passed through the xmm1 register and that's unusual. There is nothing pushed onto the stack. We can still hook the function, but we can't access its arguments.

Syntax: Select all

import memory

from memory import Convention
from memory import Argument
from memory import Return

from memory.hooks import PreHook

server = memory.find_binary('server')

deafen = server[b'\x55\x8B\xEC\x83\xEC\x28\x56\x57\x8B\xF9\xF3\x0F\x11\x4D\xFC'].make_function(
Convention.THISCALL,
(Argument.POINTER,),
Return.VOID
)

@PreHook(deafen)
def my_hook(args):
print(tuple(args))
return 0

Just wanted to let you know that I'm currently working on an update of our hooking mechanism. With that update you will be able to implement every calling convention. That means you can also implement the custom calling conventions that are used sometimes in CS:GO.

The above function (CSSPlayer::Deafen) uses a custom calling convention. That means that we can't access the argument. After the update it will be possible with a little work!

Syntax: Select all

import memory

from memory import DataType
from memory.hooks import PreHook

from _memory import Register
from _memory import CallingConvention


class x86MsCCSPlayerDeafen(CallingConvention):
def get_registers(self):
return [Register.ECX, Register.XMM1]

def get_pop_size(self):
return 0

def get_argument_ptr(self, index, registers):
if index == 0:
return registers.ecx.address
elif index == 1:
return registers.xmm1.address

raise IndexError

def argument_ptr_changed(self, index, registers):
pass

def get_return_ptr(self, registers):
pass

def return_ptr_changed(self, registers, return_ptr):
pass


server = memory.find_binary('server')

deafen = server[b'\x55\x8B\xEC\x83\xEC\x28\x56\x57\x8B\xF9\xF3\x0F\x11\x4D\xFC'].make_function(
x86MsCCSPlayerDeafen,
(DataType.POINTER, DataType.FLOAT),
DataType.VOID
)

@PreHook(deafen)
def my_hook(args):
print(tuple(args))
return 0
User avatar
L'In20Cible
Project Leader
Posts: 1533
Joined: Sat Jul 14, 2012 9:29 pm
Location: Québec

Postby L'In20Cible » Sun Apr 26, 2015 8:57 pm

That's awesome, good job! :D
User avatar
BackRaw
Senior Member
Posts: 537
Joined: Sun Jul 15, 2012 1:46 am
Location: Germany
Contact:

Postby BackRaw » Fri May 22, 2015 1:01 am

As for the current release (May 19th), how would I go about it because of the changes? :grin:

I thought about something like this for the player problem:

Syntax: Select all

class PlayerDefean(object):
"""Takes care of the 'there must be a player on the server' problem."""

def __init__(self):
self.player = None

def set_player(self, index):
if index is None and self.player is not None:
self.player = None

return

self.player = PlayerEntity(index)

@PreHook(defean.player.defean)
def pre_defan(args):
player_index = index_from_pointer(args[0])
player = PlayerEntity(player_index)

echo_console('PreDefean: ' + player.name)

# Store an instance of PlayerDefean
defean = PlayerDefean()

I have a question though: When I do the PreHook(), does it do it globally - at loading time or something, or actually at the point when I'm calling defean.set_player()? I can test it in an hour or so lol.
My Github repositories:

Source.Python: https://github.com/backraw
User avatar
Ayuto
Project Leader
Posts: 2195
Joined: Sat Jul 07, 2012 8:17 am
Location: Germany

Postby Ayuto » Fri May 22, 2015 5:48 pm

In that case the hook will be initialized everytime deafen.set_player() will be called. PreHook should only be used at the global scope, because it's a sublcass of AutoUnload and all objects of this class only get properly unloaded if they are at the global scope.

However, we haven't changed hooking CCSPlayer::Deafen(), but now you are able to use this code. http://forums.sourcepython.com/showthread.php?754-How-to-reset-the-player-s-sound-to-normal-on-player_blind&p=4716&viewfull=1#post4716
User avatar
BackRaw
Senior Member
Posts: 537
Joined: Sun Jul 15, 2012 1:46 am
Location: Germany
Contact:

Postby BackRaw » Sat May 23, 2015 12:20 am

Ayuto wrote:In that case the hook will be initialized everytime deafen.set_player() will be called. PreHook should only be used at the global scope, because it's a sublcass of AutoUnload and all objects of this class only get properly unloaded if they are at the global scope.

However, we haven't changed hooking CCSPlayer: :D eafen(), but now you are able to use this code. http://forums.sourcepython.com/showthread.php?754-How-to-reset-the-player-s-sound-to-normal-on-player_blind&p=4716&viewfull=1#post4716


Very cool, thanks.
My Github repositories:

Source.Python: https://github.com/backraw
User avatar
BackRaw
Senior Member
Posts: 537
Joined: Sun Jul 15, 2012 1:46 am
Location: Germany
Contact:

Postby BackRaw » Sat May 23, 2015 12:54 am

I guess that's a Windows signature, my Linux server can't find it. :(
My Github repositories:

Source.Python: https://github.com/backraw
User avatar
satoon101
Project Leader
Posts: 2697
Joined: Sat Jul 07, 2012 1:59 am

Postby satoon101 » Sat May 23, 2015 1:14 am

If you don't need the other arguments, you don't really 'need' to use that example. For your last posted code, maybe try this instead:

Syntax: Select all

from events import Event
from filters.players import PlayerIter
from memory import make_object
from memory.hooks import HookType
from players.entity import PlayerEntity
from players.helpers import index_from_userid


_deafen_function = None


def pre_deafen(args):
player = make_object(PlayerEntity, args[0])
print('PreDeafen:', player.name)


for _player in PlayerIter(return_types='player'):
_deafen_function = _player.deafen
_deafen_function.add_hook(HookType.PRE, pre_deafen)
break

@Event
def player_activate(game_event):
global _deafen_function
if _deafen_function is not None:
return
player = PlayerEntity(index_from_userid(game_event.get_int('userid')))
_deafen_function = player.deafen
_deafen_function.add_hook(HookType.PRE, pre_deafen)


def unload():
if _deafen_function is not None:
_deafen_function.remove_hook(HookType.PRE, pre_deafen)



*Edit: we are working on a couple new decorators that will allow you to hook these types of functions once an entity of the specified type is created on the server. There is still a lot of work to do on it, though. The usage of these decorators 'might' end up looking something like this:

Syntax: Select all

from entities.hooks import EntityPreHook


@EntityPreHook('player', 'deafen')
def pre_deafen(args):
...
Image
User avatar
BackRaw
Senior Member
Posts: 537
Joined: Sun Jul 15, 2012 1:46 am
Location: Germany
Contact:

Postby BackRaw » Sat May 23, 2015 2:14 am

satoon101 wrote:If you don't need the other arguments, you don't really 'need' to use that example. For your last posted code, maybe try this instead:

Syntax: Select all

from events import Event
from filters.players import PlayerIter
from memory import make_object
from memory.hooks import HookType
from players.entity import PlayerEntity
from players.helpers import index_from_userid


_deafen_function = None


def pre_deafen(args):
player = make_object(PlayerEntity, args[0])
print('PreDeafen:', player.name)


for _player in PlayerIter(return_types='player'):
_deafen_function = _player.deafen
_deafen_function.add_hook(HookType.PRE, pre_deafen)
break

@Event
def player_activate(game_event):
global _deafen_function
if _deafen_function is not None:
return
player = PlayerEntity(index_from_userid(game_event.get_int('userid')))
_deafen_function = player.deafen
_deafen_function.add_hook(HookType.PRE, pre_deafen)


def unload():
if _deafen_function is not None:
_deafen_function.remove_hook(HookType.PRE, pre_deafen)
Great! I'm using this now, I'll test tomorrow :)


*Edit: we are working on a couple new decorators that will allow you to hook these types of functions once an entity of the specified type is created on the server. There is still a lot of work to do on it, though. The usage of these decorators 'might' end up looking something like this:

Syntax: Select all

from entities.hooks import EntityPreHook


@EntityPreHook('player', 'deafen')
def pre_deafen(args):
...
This looks promising, I like it.
My Github repositories:

Source.Python: https://github.com/backraw
User avatar
Ayuto
Project Leader
Posts: 2195
Joined: Sat Jul 07, 2012 8:17 am
Location: Germany

Postby Ayuto » Sat May 23, 2015 7:07 am

BackRaw wrote:I guess that's a Windows signature, my Linux server can't find it. :(

Yes, this extra work is only required for CS:GO on Windows (if you want to access the argument).
User avatar
BackRaw
Senior Member
Posts: 537
Joined: Sun Jul 15, 2012 1:46 am
Location: Germany
Contact:

Postby BackRaw » Sat May 23, 2015 10:44 am

Does return 0 i the pre-hook block the defean function? If so, then I don't need any argument and I'll stick to the way Satoon provided :)
My Github repositories:

Source.Python: https://github.com/backraw
User avatar
Ayuto
Project Leader
Posts: 2195
Joined: Sat Jul 07, 2012 8:17 am
Location: Germany

Postby Ayuto » Sat May 23, 2015 10:52 am

Yep, it does. :)

Return to “Plugin Development Support”

Who is online

Users browsing this forum: No registered users and 51 guests