Command crashes with object methods.

All other Source.Python topics and issues.
Omega_K2
Senior Member
Posts: 227
Joined: Sat Jul 07, 2012 3:05 am
Location: Europe
Contact:

Command crashes with object methods.

Postby Omega_K2 » Sat Dec 01, 2012 4:33 pm

Both, client and server commands will crash the server if you use a object method as callback.

In this sample code, passing object method b.prt (of class B) will crash

Syntax: Select all

from Source import ClientCmd

class A(object):
def __init__(self, x):
self.x = x
def __call__(self, entity, command):
print(self.x)
return ClientCmd.ClientCommandReturn.CONTINUE

class B(object):
def __init__(self, x):
self.x = x
def prt(self, entity, command):
print(self.x)
return ClientCmd.ClientCommandReturn.CONTINUE

def C(entity, command):
print("C")
return ClientCmd.ClientCommandReturn.CONTINUE

a = A("A")
b = B("B")

clientcmd = ClientCmd.GetClientCommand("test")

def load():
clientcmd.AddToEnd(a)
clientcmd.AddToEnd(b.prt)
clientcmd.AddToEnd(C)

def unload():
clientcmd.Remove(a)
clientcmd.Remove(b.prt)
clientcmd.Remove(C)
Libraries: k2tools
Plugins (any): GSRPG (soon) | Pretty Status List | MySQLAds (soon)
Plugins (game-specific): None atm

If you happen to find a bug or need help, either post in the release threads or contact me in IRC gamesurge.net:6667 / #sourcepython
User avatar
satoon101
Project Leader
Posts: 2697
Joined: Sat Jul 07, 2012 1:59 am

Postby satoon101 » Sun Dec 02, 2012 1:03 am

I have actually (locally) rewritten the Python API for command registration. To enable auto returning CONTINUE, I use a method of the instanciating class to call the actual registered callback. Currently, though, it actually calls the unregister method. I think there is something a bit off about the memory locations for many different aspects of the plugin, currently. Much like how using ServerVar() and passing a string for the help text is never correct. I think this is why the crashing is occurring as well, as it is trying to access the wrong memory location. This is all just a theory, currently, but it is the only thing that seems plausible to me for all these issues.

Satoon
User avatar
satoon101
Project Leader
Posts: 2697
Joined: Sat Jul 07, 2012 1:59 am

Postby satoon101 » Tue Dec 04, 2012 4:59 pm

Nevermind what I said, I got it to work just fine. The latest update works for the following:

Syntax: Select all

from commands.server import ServerCommand
from commands.client import ClientCommand

@ClientCommand('jointeam')
def jointeam_hook(entity, command):
print('JOIN TEAM!!!')
print(entity)
print(command)
print(command.ArgS())
return True

@ServerCommand('thistest', 'Description')
def server_command_test(command):
print(command)
print(command.ArgS())
Obviously this doesn't fix your issue, but it uses methods internally and works perfectly fine...

Through some testing, it seems as if "self" is actually the class method and not the class instance. I am not fully certain why that is, but using type(self) revealed that. Even without that, and using:

Syntax: Select all

from Source import Cvar

class _Test(object):
def __init__(self, name):
self.name = name
command.AddToEnd(self.callback)
def callback(self, CCommand):
print('Callback works!!')
print(CCommand)
print(CCommand.ArgS())
return Cvar.CommandReturn.CONTINUE

command = Cvar.GetCommand('thistest', 'This is a test command', 0)

Test = _Test('this is a test')
I get all of the print statements to work fine, but it still crashes... Changing the code to use self and __call__, self is the class instance, as it should be, and it does not crash.

I am really unsure why this would be happening, though, but we will continue to investigate.

Satoon
Omega_K2
Senior Member
Posts: 227
Joined: Sat Jul 07, 2012 3:05 am
Location: Europe
Contact:

Postby Omega_K2 » Tue Dec 04, 2012 10:44 pm

Hm, that could be what I was thinking about this error earlier. Assumung this:

Syntax: Select all

class A(object):
def __init__(self):
pass
def prt(self):
print(type(self), self)


Both options of calling prt are equivalent:

Syntax: Select all

>>> b = A()
>>> b.prt()
<class '__main__.A'> <__main__.A object at 0x02A0BD10>
>>> A.prt(b)


Maybe it passes the wrong parameters which causes it to crash (later) on? Is this what you are getting as type?

Syntax: Select all

>>> A.prt(A.prt)
<class 'function'> <function prt at 0x02A0EC00>


Though I'm not sure why this isn't the case for __call__ methods. Maybe it is because functions are actually classes as well and have that __call__ method ( so anything that is callable, has that method!) and boost/SPE considers the default and passes the object properly in that case, but not when a different method is used.

EDIT: Since it's possible to use both normal functions and classes with a __call__ I can still circumvent this problem, though it sill poses a bug that causes a crash :(
Libraries: k2tools

Plugins (any): GSRPG (soon) | Pretty Status List | MySQLAds (soon)

Plugins (game-specific): None atm



If you happen to find a bug or need help, either post in the release threads or contact me in IRC gamesurge.net:6667 / #sourcepython

Return to “General Discussion”

Who is online

Users browsing this forum: No registered users and 12 guests