TGEA 1.7 Python Support
by Prairie Games · in Torque Game Engine Advanced · 03/29/2008 (11:28 am) · 75 replies
Hey all, been doing some R&D on a new project and wanted to try out the (awesome) new build system
included with TGEA 1.7
I also wanted to have a look at some embedded scripting... and so dusted off PyTorque, got it ported over to 1.7, changed it around to be an embedded system, and hooked it up with the new build system.

There are only very minor changes necessary to the core engine to support Python scripting. It is pretty powerful stuff... the docs are a bit sparse, but if you head over to MMOWorkshop.com you can browse through a lot of examples...
BTW, this is a newer system than what was used for Minions of Mirth. It is actually quite a bit cleaner... so, when in doubt check out the included example.py :)
You can snag PyTorque for TGEA 1.7 HERE
This was a pretty quick package job... so, post here with any glaring issues.
-Prairie Games, Inc
included with TGEA 1.7
I also wanted to have a look at some embedded scripting... and so dusted off PyTorque, got it ported over to 1.7, changed it around to be an embedded system, and hooked it up with the new build system.

There are only very minor changes necessary to the core engine to support Python scripting. It is pretty powerful stuff... the docs are a bit sparse, but if you head over to MMOWorkshop.com you can browse through a lot of examples...
BTW, this is a newer system than what was used for Minions of Mirth. It is actually quite a bit cleaner... so, when in doubt check out the included example.py :)
You can snag PyTorque for TGEA 1.7 HERE
This was a pretty quick package job... so, post here with any glaring issues.
-Prairie Games, Inc
#22
pytorque.export() - non-string namespace
I am playing around with trying to get more info out of it, if there is any more to get.
04/16/2008 (6:37 pm)
Yes, it throws an exception. When I catch it the game doesn't crash. When I echo the exception, it resolves to the following string:pytorque.export() - non-string namespace
I am playing around with trying to get more info out of it, if there is any more to get.
#23
pytorque.export(PyHelloWorld, "", "PyHelloWorld", "Just has python echo to the console.", 1, 1)
04/16/2008 (6:58 pm)
Try: pytorque.export(PyHelloWorld, "", "PyHelloWorld", "Just has python echo to the console.", 1, 1)
#24
(0): Unable to find function PyHelloWorld
04/16/2008 (7:10 pm)
It no longer throws an exception. But it doesn't seem to export either. If I type PyHelloWorld() in the console, it says:(0): Unable to find function PyHelloWorld
#25
pytorque.export(PyHelloWorld, "PyHelloWorld", "Just has python echo to the console.", 1, 1)
That should export to global namespace.
Also, try:
pytorque.export(PyHelloWorld, "PyHelloWorld", "Just has python echo to the console.", 0, 0)
If you get complaints about incorrect number of args...
04/16/2008 (8:18 pm)
Try:pytorque.export(PyHelloWorld, "PyHelloWorld", "Just has python echo to the console.", 1, 1)
That should export to global namespace.
Also, try:
pytorque.export(PyHelloWorld, "PyHelloWorld", "Just has python echo to the console.", 0, 0)
If you get complaints about incorrect number of args...
#27
04/17/2008 (5:59 am)
Great, should probably allow the None, "" forms as well... when in doubt, check the C++ sources for the console bindings... there's only 16k of source there so it shouldn't be too bad ;)
#28
Unaware if someone posted the fix yet for pytorque exports, here is the fixed code.
pytorque.cpp line 279
Old Code
New Code
As you can see PyTuple_New became PyTuple_New(argc)
and in the iteration loop your condition changed to i<=argc
Seems to work with 0 arguments, and other numbers as well, YMMV though.
05/14/2008 (12:04 pm)
Argument PassingUnaware if someone posted the fix yet for pytorque exports, here is the fixed code.
pytorque.cpp line 279
Old Code
if (argc > 1)
args = PyTuple_New(argc-1);
for (int i=1;i<argc;i++)New Code
if (argc > 1)
args = PyTuple_New(argc);
// argument fix
for (int i=1;i<=argc;i++)As you can see PyTuple_New became PyTuple_New(argc)
and in the iteration loop your condition changed to i<=argc
Seems to work with 0 arguments, and other numbers as well, YMMV though.
#29
05/14/2008 (12:16 pm)
Thanks, I think there may have been console side changes that affected this from TGE 1.5/TGEA 1.0.3 -> 1.7
#30
I'm desperate to get this Python suport runnin; but am hitting this problem at the linking stage on a VS 2008 express compile:
sfxDSDevice.obj : error LNK2019: unresolved external symbol "public: static class SFXDSVoice * __cdecl SFXDSVoice::create(class SFXDSBuffer *)" (?create@SFXDSVoice@@SAPAV1@PAVSFXDSBuffer@@@Z) referenced in function "public: virtual class SFXVoice * __thiscall SFXDSDevice::createVoice(class SFXBuffer *)" (?createVoice@SFXDSDevice@@UAEPAVSFXVoice@@PAVSFXBuffer@@@Z)
sfxNullDevice.obj : error LNK2019: unresolved external symbol "protected: __thiscall SFXNullVoice::SFXNullVoice(void)" (??0SFXNullVoice@@IAE@XZ) referenced in function "public: virtual class SFXVoice * __thiscall SFXNullDevice::createVoice(class SFXBuffer *)" (?createVoice@SFXNullDevice@@UAEPAVSFXVoice@@PAVSFXBuffer@@@Z)
sfxALDevice.obj : error LNK2019: unresolved external symbol "public: static class SFXALVoice * __cdecl SFXALVoice::create(class SFXALBuffer *)" (?create@SFXALVoice@@SAPAV1@PAVSFXALBuffer@@@Z) referenced in function "public: virtual class SFXVoice * __thiscall SFXALDevice::createVoice(class SFXBuffer *)" (?createVoice@SFXALDevice@@UAEPAVSFXVoice@@PAVSFXBuffer@@@Z)
../../../game/PyTorque.exe : fatal error LNK1120: 3 unresolved externals
I went and rebuild the engine with another project and that worked perfectly, also using the T3D project files from the pyTorque project worked; I'm so nearly there but being beaten at the last hurdle.
Can someone shed some light !?!?!?!
06/07/2008 (9:38 am)
Guys,I'm desperate to get this Python suport runnin; but am hitting this problem at the linking stage on a VS 2008 express compile:
sfxDSDevice.obj : error LNK2019: unresolved external symbol "public: static class SFXDSVoice * __cdecl SFXDSVoice::create(class SFXDSBuffer *)" (?create@SFXDSVoice@@SAPAV1@PAVSFXDSBuffer@@@Z) referenced in function "public: virtual class SFXVoice * __thiscall SFXDSDevice::createVoice(class SFXBuffer *)" (?createVoice@SFXDSDevice@@UAEPAVSFXVoice@@PAVSFXBuffer@@@Z)
sfxNullDevice.obj : error LNK2019: unresolved external symbol "protected: __thiscall SFXNullVoice::SFXNullVoice(void)" (??0SFXNullVoice@@IAE@XZ) referenced in function "public: virtual class SFXVoice * __thiscall SFXNullDevice::createVoice(class SFXBuffer *)" (?createVoice@SFXNullDevice@@UAEPAVSFXVoice@@PAVSFXBuffer@@@Z)
sfxALDevice.obj : error LNK2019: unresolved external symbol "public: static class SFXALVoice * __cdecl SFXALVoice::create(class SFXALBuffer *)" (?create@SFXALVoice@@SAPAV1@PAVSFXALBuffer@@@Z) referenced in function "public: virtual class SFXVoice * __thiscall SFXALDevice::createVoice(class SFXBuffer *)" (?createVoice@SFXALDevice@@UAEPAVSFXVoice@@PAVSFXBuffer@@@Z)
../../../game/PyTorque.exe : fatal error LNK1120: 3 unresolved externals
I went and rebuild the engine with another project and that worked perfectly, also using the T3D project files from the pyTorque project worked; I'm so nearly there but being beaten at the last hurdle.
Can someone shed some light !?!?!?!
#31
So, in order to make things work as-far-as-I-can-tell, you need to go through every project in your VS solution, change them to Multi-Threaded DLLs and also change the name of the file created from being a .exe to a .pyd. After a clean build you should be able to run the following script...
Not sure if all this is how things work in the TGEA bindings, but at least this is how things work with the old TGE ones.
Edit: fixed some typos after actually reading the example script heh
06/07/2008 (4:48 pm)
I personally haven't tried this in TGEA but in TGE with the Python bindings from Prairie Games (dunno if this is even the same style of bindings) we don't compile the engine as an executable; instead it's compiled as a Multi-Threaded DLL and then loaded by a Python script which you can then compile with any of PyInstaller, Py2Exe, Py2App and so forth.So, in order to make things work as-far-as-I-can-tell, you need to go through every project in your VS solution, change them to Multi-Threaded DLLs and also change the name of the file created from being a .exe to a .pyd. After a clean build you should be able to run the following script...
# assuming your compiled DLL is named "pytorque.pyd" and
# exists in the same directory as this script...
import pytorque
import sys
def main():
pytorque.initialize()
while pytorque.tick():
pass
pytorque.shutdown()
sys.exit()
if __name__ == "__main__":
main()Not sure if all this is how things work in the TGEA bindings, but at least this is how things work with the old TGE ones.
If this helps:
cheers()
else:
sorry()Edit: fixed some typos after actually reading the example script heh
#32
So i'm still stuck with build troubles
06/07/2008 (4:59 pm)
Thanks for the response; however with the TGEA 1.7 python support they are embedding the interpreter into C rather than extending python with a dll.So i'm still stuck with build troubles
#33
06/07/2008 (5:00 pm)
In this particular version it is embedded into TGEA as an executable and thus doesn't require it to be multi-threaded DLL. I'm not sure what the issue that Alitair is having though, I haven't tried compiling with VS2008 though.
#34
I havn't tested any python stuff yet, but the executable seems to work
06/07/2008 (5:39 pm)
--phew just sorted it, I can't work out what went wrong; but the solution was to generate a new T3D project using the generateprojects.bat file , then add the python include directories etc by hand.I havn't tested any python stuff yet, but the executable seems to work
#35
Correct code pytorque.cpp line 273
BAD CODE
06/20/2008 (8:16 am)
Just realized I was an idiot and forgot to fix one more case of arguments, look at line 273 and make sure you correct the conditional to create your tuples. It should be >= 1, NOT > 1. If you ever pass a single argument it will crash due to an access violation.Correct code pytorque.cpp line 273
// number of arguments fix
if (argc >= 1)
args = PyTuple_New(argc);BAD CODE
// number of arguments fix
if (argc > 1)
args = PyTuple_New(argc);
#36
Some info:
*Any python error un main.py cause engine crash with "out of bins" error on console.log. I put my test code in run.py
*Python can't access dyn fields. SOLVED.
*For create dyn fileds, use TorqueObject.setFieldValue(fieldname,value)
*Python can't access methods in object name namescape. SOLVED
*All vars recieved from a exported function are strings. It's necesary to check and convert types.
*Callbacks methods exported recieve console object ID as string. Added TorqueObject(ID as string) for facilitate creation.
*Memory leak and a error in PyTorqueObject_call that cause string used in argv are deleted before they are used. SOLVED
*Change pytorque.export(callback,[namespace],functionname,usagedoc,minargs,maxargs) for add funtionality of override console method. You can define important engine callback as onAdd, onRemove, onCollide... etc.
*Exported callbacks check methods in all class inheritance
*main.py example for test all features. WORKING ON THIS
*Port to 1.7.1 WORKING ON THIS
Updated version of pytoque.cpp
main.py
SORRY FOR MY BAD ENGLISH T_T
06/28/2008 (10:14 am)
Thx for your work, i love TGEA 1.7 + PYTHON :DSome info:
*Any python error un main.py cause engine crash with "out of bins" error on console.log. I put my test code in run.py
*Python can't access dyn fields. SOLVED.
*For create dyn fileds, use TorqueObject.setFieldValue(fieldname,value)
*Python can't access methods in object name namescape. SOLVED
*All vars recieved from a exported function are strings. It's necesary to check and convert types.
*Callbacks methods exported recieve console object ID as string. Added TorqueObject(ID as string) for facilitate creation.
*Memory leak and a error in PyTorqueObject_call that cause string used in argv are deleted before they are used. SOLVED
*Change pytorque.export(callback,[namespace],functionname,usagedoc,minargs,maxargs) for add funtionality of override console method. You can define important engine callback as onAdd, onRemove, onCollide... etc.
*Exported callbacks check methods in all class inheritance
*main.py example for test all features. WORKING ON THIS
*Port to 1.7.1 WORKING ON THIS
Updated version of pytoque.cpp
main.py
#--- Torque Python Module Example ---
#Any error in this file cause a engine crash with a "out of bins" mensage in console.log
#Torque as a standard Python extension (no longer a executable)
import pytorque
import sys
class ConsoleLog:
def __init__(self):
self.file = open('pytest.log','w')
def write(self, stuff):
self.file.write(stuff)
if stuff != "\n": #print(string) double call write, 1 for "string" and 2 for "\n"
pytorque.evaluate('echo("%s");'%stuff)
sys.stdout = ConsoleLog()
sys.stderr = ConsoleLog()
#initialize pytorque, this also executes main.cs and the .cs packages
pytorque.initialize()
pytorque.evaluate('echo("%s");'%pytorque.__doc__)
try:
import run
except:
pytorque.evaluate('echo("RUN ERROR: %s");'%sys.exc_info()[1])
#the main loop is broken out and can be combined with other frameworks rather easily
while pytorque.tick():
pass
#cleanup pytorque.. goodbye!
pytorque.shutdown()SORRY FOR MY BAD ENGLISH T_T
#37
06/28/2008 (5:43 pm)
Nice list of fixes here.
#38
Updated version of pytoque.cpp
06/29/2008 (2:15 am)
*Add get/set dynamics fields but can't create in pythonUpdated version of pytoque.cpp
def py_OnButton(v1,v2,v3):
value = v1+v2+v3
pytorque.evaluate('echo("button click: %s");'%value)
pytorque.export(py_OnButton,"ts_OnButton","Example button command2",3,3)
pytorque.evaluate('ts_OnButton(3,4,5);') #345 on console.log O_O
py_OnButton(3,4,5) #12 on console.log
#39
error C2446: '!=' : no conversion from 'const char *' to 'const AbstractClassRep::Field *'
I'm guessing theres some additional changes above it.
06/29/2008 (2:39 am)
Another nice addition. Though with the way you have things pasted in there, I can't get the latest changes to work. Would probalby be easier if you copied the entire function in there (getattr/setattr) as it may be missing some code or something that was previously changed. I can't get it to compile. It gets this error:error C2446: '!=' : no conversion from 'const char *' to 'const AbstractClassRep::Field *'
I'm guessing theres some additional changes above it.
#40
06/29/2008 (2:55 am)
Ok, sorry if some code are wrong. I update it with var types solved and a main.py for test all features
Torque Owner Prairie Games
Prairie Games, Inc.