TGEPython - Torque/Python
by Prairie Games · in Technical Issues · 12/05/2002 (3:20 am) · 37 replies
I have written some front matter for TGEPython - an industrial strength Torque/Python binding.
*** Sorry, over the years we've lost this file. Please forward to Support@PrairieGames.com, thank you!
You can find it: HERE
Cheers,
-Joshua Ritter
Prairie Games, Inc.
*** Sorry, over the years we've lost this file. Please forward to Support@PrairieGames.com, thank you!
You can find it: HERE
Cheers,
-Joshua Ritter
Prairie Games, Inc.
#2
Keep up the good work. TGEPython alone was incredible... this is even better :)
12/05/2002 (7:38 am)
Awesome!Keep up the good work. TGEPython alone was incredible... this is even better :)
#3
However there is trouble in paradise. Though I have followed all of the installation instructions, the code crashes with;
Unhandled exception in Torquedemo_debug.exe
"python22.dll": 0xc000005: Access violation
This happens when PyInit is called. Has anyone seen this, and how exactly does the PyInit initialize the python interpreter?
Arena of Sorcery Developer,
Chris Christenson
12/31/2002 (8:13 am)
First, Josh you are a God for incorporating Python with Torque (in my humble opinion as the best scripting language).However there is trouble in paradise. Though I have followed all of the installation instructions, the code crashes with;
Unhandled exception in Torquedemo_debug.exe
"python22.dll": 0xc000005: Access violation
This happens when PyInit is called. Has anyone seen this, and how exactly does the PyInit initialize the python interpreter?
Arena of Sorcery Developer,
Chris Christenson
#4
Make sure you have followed this installation direction: Did you switch to (debug) multithreaded dll code generation?
Email me your call stack and the line of code you crash on if you are stuck...
Vibes,
-J
12/31/2002 (10:29 am)
Thanks :)Make sure you have followed this installation direction: Did you switch to (debug) multithreaded dll code generation?
Email me your call stack and the line of code you crash on if you are stuck...
Vibes,
-J
#5
I'm trying to create a python class derrived from AIPlayer but I'm not having much luck. I keep getting an error saying that the module has no pyExec attribute.
Here's what I've got so far:
I added the following to simobject.py
Then created a file pyd20player.py with the following:
I put a call to the initialize with right after the weapon initialization as well as a pyexec call for the new python script in my cs scripts.
Any ideas?
12/31/2002 (8:46 pm)
Joshua,I'm trying to create a python class derrived from AIPlayer but I'm not having much luck. I keep getting an error saying that the module has no pyExec attribute.
Here's what I've got so far:
I added the following to simobject.py
class AIPlayer(SimObject):
def __init__(self,classname="AIPlayer",objectname="Anonymous"):
SimObject.__init__(self,classname,objectname)
self.registerObject(AIPlayer)Then created a file pyd20player.py with the following:
from tgenative import *
from tgepython.console.simobject import *
class pyD20Player(AIPlayer):
def __init__(self,objectname="pyD20Player"):
AIPlayer.__init__(self,objectname)
db=self._tge
TGEExport(pyD20Player.onSpawn,objectname,"onSpawn","poot",2,2)
self.registerObject(pyD20Player)
def OnSpawn(self,args):
print "Python OnSpawnCalled"
def Initialize():
pyD20Player()I put a call to the initialize with right after the weapon initialization as well as a pyexec call for the new python script in my cs scripts.
Any ideas?
#6
def PyExec():
entry point in the .py file you are PyExec()ing from .cs ... if it is called pyExec() the default PyExec() call from the .cs won't find the function. It's case sensitive, see the docs on PyExec(), you can specify your own entry point if you like.. or multiple points into the same file... :)
I find that I don't really use PyExec much, this is generally for mixing .cs and Python code... it is also useful for making GUI's that have Python callbacks... something I do quite a bit of... *SMALL NOTE* unfortunately you can't use the Namespace field when exporting these functions with the released version of TGEPython, as I had to modify Torque to do this... so basically you end up with functions like MainMenu_OnJoin instead of a namespace function like MainMenu::OnJoin ... no big deal really... though, if people want this ability I could paste the code changes necessary.
It's generally best just to work in Python. ie. create a Python main loop that drives TGE with:
TGECall("schedule",1000*timeout,0,"MyPythonMainLoop")
There are LOTS of TGEPython examples on the way with the initial release of the ActionRPG Framework... stay tuned :)
-J
12/31/2002 (9:33 pm)
Do you have a def PyExec():
entry point in the .py file you are PyExec()ing from .cs ... if it is called pyExec() the default PyExec() call from the .cs won't find the function. It's case sensitive, see the docs on PyExec(), you can specify your own entry point if you like.. or multiple points into the same file... :)
I find that I don't really use PyExec much, this is generally for mixing .cs and Python code... it is also useful for making GUI's that have Python callbacks... something I do quite a bit of... *SMALL NOTE* unfortunately you can't use the Namespace field when exporting these functions with the released version of TGEPython, as I had to modify Torque to do this... so basically you end up with functions like MainMenu_OnJoin instead of a namespace function like MainMenu::OnJoin ... no big deal really... though, if people want this ability I could paste the code changes necessary.
It's generally best just to work in Python. ie. create a Python main loop that drives TGE with:
TGECall("schedule",1000*timeout,0,"MyPythonMainLoop")
There are LOTS of TGEPython examples on the way with the initial release of the ActionRPG Framework... stay tuned :)
-J
#7
01/01/2003 (4:42 am)
The problem with going all Python is that you have to start integrating somewhere. It's either rewrite every line of CS script or allow python objects to be used from cs.
#8
01/01/2003 (5:03 am)
Hmmm I guess I'll wait till you release then unless you've released additional docs... I fixed that pyexec problem only to get a whole littany of errors that gave me no real hints as to what was wrong.
#9
C++ is the primary language of Torque with .cs steering it/defining data... Python can be the primary language of your game/framework... C++ and Python are both good at what they do... but the barrier between the two shouldn't be crossed often... crossing languages is generally a design problem...
I spent a fair amount of time writing the current TGEPython docs ... they pretty much cover how to use it... the examples provided also show how to hook up some simple functionality... it's use is very much like writing TGE C++ script interfaces, though you are making your functions in Python instead of C++
I'm curious on the "littany of errors that gave me no real hints what was wrong"... I can't make TGEPython better unless I get feedback... perhaps email me these?
One question I would ask is how well do you know Python? I thought I remembered you being new to the language, TGEPython + Torque is a power tool, intermediate knowledge of Python and Torque is required... both can be gained with a little frustration :)
Hope this helps,
-J
01/01/2003 (9:40 am)
You don't have to go "all python"... which I don't recommend in the TGEPython front matter docs... primarily it is best to write new code in Python.. a constant cycle of .cs <-> .py will bring design (and likely performance) trouble... glue your Python code into Torque with PyExec().. TGEExport, TGECall, etc ... C++ is the primary language of Torque with .cs steering it/defining data... Python can be the primary language of your game/framework... C++ and Python are both good at what they do... but the barrier between the two shouldn't be crossed often... crossing languages is generally a design problem...
I spent a fair amount of time writing the current TGEPython docs ... they pretty much cover how to use it... the examples provided also show how to hook up some simple functionality... it's use is very much like writing TGE C++ script interfaces, though you are making your functions in Python instead of C++
I'm curious on the "littany of errors that gave me no real hints what was wrong"... I can't make TGEPython better unless I get feedback... perhaps email me these?
One question I would ask is how well do you know Python? I thought I remembered you being new to the language, TGEPython + Torque is a power tool, intermediate knowledge of Python and Torque is required... both can be gained with a little frustration :)
Hope this helps,
-J
#10
A lot of my begining error messages gave zero indication of the cause of the problem instead they'd take up a lot of space with blank lines and not produce meaningful output. I wish I could revert back to when I was getting those but I'm at least getting real error messages. Although a generic failed to register object error message isn't of much use without some indicator of WHY it failed.
Here's what I'm trying to implement as a test case. I have a C++ object that controls spawns for AIPlayers in a given area. This object makes a script call to a specified script function for it to generate the AIPlayer (actualy a cs script derrived AIPlayer). Once the player has been created the C++ object moves it to the proper location. After it's in position the C++ object calls the "onSpawn" function of the AIPlayer which is only implemented in cs script.
I outlined the code in a previous message. I've since fixed up the python player object to where it only gives a single "failed to register" error message. Here's the current bare bones implementation:
I have no idea why it doesn't work, and I have nothing to guide me to a solution. Even if I get it working there's still the question of being able to make a call like this from C++ "Con::execute( pPlayer, 2, gOnSpawnArgs );" neither PyExec nor PySimpleString seem to offer that basic functionality. I suppose I could implement a Python function that takes an object name as a parameter and then calls the onSpawn on that object but that's rather hackish.
Let me try this: In one our your .plans you mentioned having AIPLayer implemented in your framework, how did YOU implement them in Torque Script or Python? And what if any issues did you encounter?
And I apologize if I come across in harsh manner. This is day one of not smoking for me, which REALLY hasn't helped my problem solving abilites at all.
01/01/2003 (11:37 am)
A large part of the problem is my unfamiliarity with Python, I've not touched the language in 2-3 years although it is coming back to me. The Torque aspect isn't an issue, if I'd have sat down this morning to write C++ and cs script I'd have accomplished my goals I set out for the day it's just relearning Python + trying to learn your binding system that's got me slowed down.A lot of my begining error messages gave zero indication of the cause of the problem instead they'd take up a lot of space with blank lines and not produce meaningful output. I wish I could revert back to when I was getting those but I'm at least getting real error messages. Although a generic failed to register object error message isn't of much use without some indicator of WHY it failed.
Here's what I'm trying to implement as a test case. I have a C++ object that controls spawns for AIPlayers in a given area. This object makes a script call to a specified script function for it to generate the AIPlayer (actualy a cs script derrived AIPlayer). Once the player has been created the C++ object moves it to the proper location. After it's in position the C++ object calls the "onSpawn" function of the AIPlayer which is only implemented in cs script.
I outlined the code in a previous message. I've since fixed up the python player object to where it only gives a single "failed to register" error message. Here's the current bare bones implementation:
from tgenative import *
from tgepython.console.simobject import *
class pyD20Player(AIPlayer):
def __init__(self,objectname="Anonymous"):
AIPlayer.__init__(self,objectname)
tge = self._tge
tge.dataBlock = "LightMaleHumanArmor"
tge.aiPlayer = 1
TGEExport(pyD20Player.onSpawn,objectname,"onSpawn","poot",2,2)
self.registerObject(pyD20Player)
def onSpawn(self,args):
print "Python OnSpawnCalled"
def Initialize():
pyD20Player()
def PyExec():
Initialize()
def pyTestSpawn():
p = pyD20Player()I have no idea why it doesn't work, and I have nothing to guide me to a solution. Even if I get it working there's still the question of being able to make a call like this from C++ "Con::execute( pPlayer, 2, gOnSpawnArgs );" neither PyExec nor PySimpleString seem to offer that basic functionality. I suppose I could implement a Python function that takes an object name as a parameter and then calls the onSpawn on that object but that's rather hackish.
Let me try this: In one our your .plans you mentioned having AIPLayer implemented in your framework, how did YOU implement them in Torque Script or Python? And what if any issues did you encounter?
And I apologize if I come across in harsh manner. This is day one of not smoking for me, which REALLY hasn't helped my problem solving abilites at all.
#11
Try the below... 70% of it is comments btw... very little code to accomplish this :)
-J
01/01/2003 (2:51 pm)
I quit smoking 3 years ago... sucked...Try the below... 70% of it is comments btw... very little code to accomplish this :)
-J
from tgenative import *
from tgepython.console.simobject import AIPlayer,TGEExport
'''
AIPlayer Example:
Exports the function SpawnMyAIPlayer(); to the Torque Console
'''
class MyAIPlayer(AIPlayer):
def __init__(self,objectname):
AIPlayer.__init__(self,objectname)
tge=self._tge
tge.dataBlock="LightMaleHumanArmor"
self.registerObject(MyAIPlayer)
#Remember .cs callbacks are via datablocks!!!!!!
#The .cs datablock's onAdd will be called automatically
#Though, we are in python. We can do our game logic onAdd() here
#If you do need datablock based tge -> python callbacks you will
#need to create a new SimDataBlock; This is no different then .cs
#call our framework's onAdd()
self.onAdd()
def onAdd(self):
print "MyAIPlayer::onAdd() called."
#just for fun.. enable this to show that the AIPlayer is being garbage collected
#when killed or mission ends
#def __del__(self):
# print "MyAIPlayer::__del__() freeing object"
#Spawn an AI player in one of the mission spawn points
gNumSpawns = 0
def SpawnMyAIPlayer():
global gNumSpawns
spawnpoint=TGECall("pickSpawnPoint")
gNumSpawns+=1
name = "MyAIPlayer "+str(gNumSpawns)
ai=MyAIPlayer(name)
ai._tge.setTransform(spawnpoint)
ai._tge.setShapeName(name)
def PyExec():
TGEExport(SpawnMyAIPlayer,None,"SpawnMyAIPlayer","SpawnMyAIPlayer()",1,1)
#12
Also is there a TGEPython equivilant of "Con::execute( [pointer to object], argc, argv[] )"? If not I can use a throwCallback but I was avoiding that route so I could get away from the extra function call.
ETA: I'm wearing the patch and I STILL want to crawl out of my skin. I cannot imagine what it'd be like without it. Having an addiction for 18 years and then trying to give it up sucks soooooooooooooo much.
01/02/2003 (10:20 am)
I'm curious, why the setShapeName call in the spawn function instead of the init? Is there a particular reason or it just heppens to be there?Also is there a TGEPython equivilant of "Con::execute( [pointer to object], argc, argv[] )"? If not I can use a throwCallback but I was avoiding that route so I could get away from the extra function call.
ETA: I'm wearing the patch and I STILL want to crawl out of my skin. I cannot imagine what it'd be like without it. Having an addiction for 18 years and then trying to give it up sucks soooooooooooooo much.
#13
Could you clarify what you mean by TGEPython having const char *execute(SimObject *, S32 argc, const char *argv[])? Perhaps some .cs script of what you are trying to do? or are you trying to do something .cpp side? If from .cpp ... you just need the SimObject * and to call Con::execute normally... am I missing something?
I quit cold turkey... locked myself in my apartment, ate sunflower seeds, and played Everquest for 2 weeks straight... was pretty ugly :)
-J
01/02/2003 (11:09 am)
No reason, the shapename/transform could be set in the constructor... I just wrote this fast...Could you clarify what you mean by TGEPython having const char *execute(SimObject *, S32 argc, const char *argv[])? Perhaps some .cs script of what you are trying to do? or are you trying to do something .cpp side? If from .cpp ... you just need the SimObject * and to call Con::execute normally... am I missing something?
I quit cold turkey... locked myself in my apartment, ate sunflower seeds, and played Everquest for 2 weeks straight... was pretty ugly :)
-J
#14
1) From C++ call a function within script that returns an object. i.e. spawnAIPlayer(). In fxSpawnArea this function is named in a variable on the fxSpawnArea allowing for different functions or the same function to be called for multiple SpawnAreas. Python could be used for this function easily.
2) Manipulate the data of that object within C++. Again no problem using Python created objects as we're only dealing with data members of the base type not the derrived. In this case we modify the transform.
3) Call a member function of that object that doesn't exist in the base class. In the example here we're calling "onSpawn()" for the AIPlayer to inform it that it's safe to start AI routines and the like. This is where I don't see Python working.
A possible workround is to create base class versions of any script object functions we'd like to implement and let inheritance take care of things.
Another is to pass in a location to the spawn function right off the bat and do all of the moving etc within script.
Yet another possbility is to do a throwcallback but then I'd have to add a datablock to the fxSpawnArea class and it really doesn't need one.
01/02/2003 (11:58 am)
The syntax const char *execute(SimObject *, S32 argc, const char *argv[]) allows logic like this:1) From C++ call a function within script that returns an object. i.e. spawnAIPlayer(). In fxSpawnArea this function is named in a variable on the fxSpawnArea allowing for different functions or the same function to be called for multiple SpawnAreas. Python could be used for this function easily.
2) Manipulate the data of that object within C++. Again no problem using Python created objects as we're only dealing with data members of the base type not the derrived. In this case we modify the transform.
3) Call a member function of that object that doesn't exist in the base class. In the example here we're calling "onSpawn()" for the AIPlayer to inform it that it's safe to start AI routines and the like. This is where I don't see Python working.
A possible workround is to create base class versions of any script object functions we'd like to implement and let inheritance take care of things.
Another is to pass in a location to the spawn function right off the bat and do all of the moving etc within script.
Yet another possbility is to do a throwcallback but then I'd have to add a datablock to the fxSpawnArea class and it really doesn't need one.
#15
Note: this is of questionable value... why you would do this I don't really know :)
So for MyAIPlayer it would be:
Here is a patched top of cTGEToPythonCallback in tgePython.cc:
01/02/2003 (12:18 pm)
To export a member function callable on the object from .cs -> you export to the closest TGE C++ baseclass in the hierarchy... as you cannot define new classes in .cs ... in Python you can handle your inheritance... another option to this is to use Datablocks... or preferably just do it all in Python :)Note: this is of questionable value... why you would do this I don't really know :)
So for MyAIPlayer it would be:
class MyAIPlayer(AIPlayer):
def __init__(self,objectname):
AIPlayer.__init__(self,objectname)
tge=self._tge
tge.dataBlock="LightMaleHumanArmor"
self.registerObject(MyAIPlayer)
self.onAdd()
def onSpawn(self,args):
print "on Spawn()"
def onAdd(self):
print "MyAIPlayer::onAdd() called."
#note that TGEExports of member functions should not be in __init__ of instance
#otherwise they are called every time a instance is created! For SimDataBlocks this
#is ok, since they are only created once! Actually for them it is probably best to not do this either...
TGEExport(MyAIPlayer.onSpawn,"AIPlayer","onSpawn","onSpawn()",2,2)Here is a patched top of cTGEToPythonCallback in tgePython.cc:
static const char* cTGEToPythonCallback(SimObject *ptr, S32 argc, const char **argv)
{
//need ptr -> PyObject (SimObject binding)
GameBaseData* gbd=NULL;
if (ptr)
gbd = dynamic_cast<GameBaseData *>(ptr);
PyObject* mainargs=PyTuple_New(4);
PyObject* fargs=PyTuple_New(argc);
if (!ptr)
{
Py_INCREF(Py_None);
PyTuple_SetItem(mainargs,0,Py_None); //will be self eventually
PyTuple_SetItem(mainargs,1,PyString_FromString("Global")); //namespace Global
}
else
{
PyTuple_SetItem(mainargs,0,PyInt_FromLong(ptr->getId())); //selfid
if (gbd)
PyTuple_SetItem(mainargs,1,PyString_FromString(gbd->getName())); //namespace = Datablock Name
else
PyTuple_SetItem(mainargs,1,PyString_FromString(ptr->getNamespace()->mName)); //Namespace TGE C++ Base Class
}-J
#16
Actualy using Python for the game logic is my plan. There are a few situations where implementing what I want isn't possible with Python for example base classes. For example fxSpawnArea or fxShapeReplicator these are items that NEED to be implemented in C++ to be properly useable. Unles I'm completely off base and Python could be used to implement those items and have them integrate properly with the editors and the like in which case that's spiffy.
01/02/2003 (2:01 pm)
"Perhaps just use Python, it\'s amazing builtins, library, and dynamic elegance " (quote from your pre-edit post)Actualy using Python for the game logic is my plan. There are a few situations where implementing what I want isn't possible with Python for example base classes. For example fxSpawnArea or fxShapeReplicator these are items that NEED to be implemented in C++ to be properly useable. Unles I'm completely off base and Python could be used to implement those items and have them integrate properly with the editors and the like in which case that's spiffy.
#17
Though, I suppose being able to seamlessly call Python class methods on an object from .cs via something like
MyAIPlayer1.onSpawn();
Doesn't hurt.. unless it is abused... which it has a very high chance for... just be careful... .cs -> C++ -> Python -> C++ -> .cs isn't exactly cheap :)
-J
01/02/2003 (2:14 pm)
I used the Torque console system to attach Python... when you create your fxSpawnArea in C++ you make it just like you were going to be using it with .cs ... up to the point where you glue it into editor... (which takes minimal .cs) ... from there you can use Python for your logic... Though, I suppose being able to seamlessly call Python class methods on an object from .cs via something like
MyAIPlayer1.onSpawn();
Doesn't hurt.. unless it is abused... which it has a very high chance for... just be careful... .cs -> C++ -> Python -> C++ -> .cs isn't exactly cheap :)
-J
#18
But somehow I've managed to cause the TGEPython engine to assert on startup "AssertFatal(gTGECall,"Invalid TGECallback");" without having edited any of the Python C++ code.
01/02/2003 (3:23 pm)
I think you misunderstand me. I have zero desire to call python objects from cs script. I only desire two things 1) To be able to execute the a member function of a python object from C++ like I can a cs object. and 2) To be able to get a return value from a Python function in C++.But somehow I've managed to cause the TGEPython engine to assert on startup "AssertFatal(gTGECall,"Invalid TGECallback");" without having edited any of the Python C++ code.
#19
//these should be valid after TGEInit call above
AssertFatal(gTGECall,"Invalid TGECallback");
AssertFatal(gTGEDelete,"Invalid TGEDelete");
specifically:
"tgenative.TGEInit(TGE.TGECallback,TGE.TGEDelete)\n" which ends up in:
Are you getting a traceback?
-J
01/02/2003 (3:54 pm)
Something probably went wrong in your tgepython.console.simobject that is causing it not to be imported properly... see the PyRun_SimpleString above..://these should be valid after TGEInit call above
AssertFatal(gTGECall,"Invalid TGECallback");
AssertFatal(gTGEDelete,"Invalid TGEDelete");
specifically:
"tgenative.TGEInit(TGE.TGECallback,TGE.TGEDelete)\n" which ends up in:
PyObject* tgePyCmd_inittge( PyObject *self, PyObject *args)
{
gTGECall=PyTuple_GetItem(args,0);
gTGEDelete=PyTuple_GetItem(args,1);
Py_INCREF(Py_None);
return Py_None;
}Are you getting a traceback?
-J
#20
My attempt to create an AIPlayer in simboject.py was causing the assertion. I had been mucking around earlier and hosed it up.
Apparently I've still got it wrong though. Since using your class generates the following errors:

Think you could slip me an updated simobject.py?
01/02/2003 (3:57 pm)
Found the problem...My attempt to create an AIPlayer in simboject.py was causing the assertion. I had been mucking around earlier and hosed it up.
Apparently I've still got it wrong though. Since using your class generates the following errors:

Think you could slip me an updated simobject.py?
Torque Owner J. Donavan Stanley