PyTGE (also PyTSE) - Python Bindings
by Prairie Games · in Torque Game Engine · 07/12/2006 (2:38 am) · 101 replies
I've had a number of requests for this so here it is sooner rather than later... Python bindings for TGE/TSE and probably TGB:
http://www.prairiegames.com/pytse10a.zip
It's called PyTSE, though there isn't any TSE specific source in it. So, it should build with no modifications with TGE 1.4
This hasn't been field tested, though it should be more or less bug free. Here's the text from the readme.txt, it's sparse I know. Time is a very limited commodity :|
Here are some minimal docs in the forum of example usage, replace TSE with TGE if that is your desire:
-Josh Ritter
Prairie Games, Inc
http://www.prairiegames.com/pytse10a.zip
It's called PyTSE, though there isn't any TSE specific source in it. So, it should build with no modifications with TGE 1.4
This hasn't been field tested, though it should be more or less bug free. Here's the text from the readme.txt, it's sparse I know. Time is a very limited commodity :|
Quote:This is a new TGE/TSE (and probably TGB) Python binding I have been working on. You can do with it what you like.
I don't have any time to document it. Though, the source file is only 16k, so it should be pretty clear.
I've also included a diff of source changes. They should be pretty close to the current HEAD revision.
You need to change your build target to a shared library (a dll on windows, also change to multithreaded dll code generation for this platform)
Here are some minimal docs in the forum of example usage, replace TSE with TGE if that is your desire:
[b]#--- TSE Python Module Example ---[/b]
[b]#TSE as a standard Python extension (no longer a executable)[/b]
import pytse
[b]#initialize pytse, this also executes main.cs and the .cs packages[/b]
pytse.initialize()
[b]#example of executing a script file[/b]
f = file("myscript.cs","rb")
script = f.read()
f.close()
pytse.evaluate(script)
[b]#or, just generate the cs code right inside Python![/b]
pytse.evaluate("""
new GuiBitmapButtonCtrl(MyButton) {
profile = "GuiButtonProfile";
horizSizing = "right";
vertSizing = "bottom";
position = "404 361";
extent = "285 85";
minExtent = "8 2";
visible = "1";
text = "Button";
groupNum = "-1";
buttonType = "PushButton";
bitmap = "./button";
helpTag = "0";
};""")
[b]#it's easy to grab a reference to the button we created[/b]
button = TSEObject("MyButton")
[b]#buttons are kind of worthless without commands. Let's make one:[/b]
def OnMyButton(value):
print "Button pushed with value",value
[b]#export the function to the console system in much the same way the C++ system does...
#we also support optional namespaces, usage documentation, and min/max args[/b]
pytse.export(OnMyButton,"MyButton","OnButton","Example button command",1,1)
[b]#we can get and set fields (including dynamic fields). We'll set our button's command:[/b]
button.command = "MyButton::OnButton(42);"
[b]#we can call console methods on our TSEObjects... So, let's simulate a button click.
#the OnMyButton function will be called with the value 42 :)[/b]
button.performClick()
[i]#note that getting an object reference to the button and setting the command like this is
purely for illustration. You can also: command = "MyButton::OnButton(42);" in the evaluated code.[/i]
[b]#moving on, we can get and set global variables[/b]
pytse.setglobal("$MyVariable",42)
print pytse.getglobal("$MyVariable")
pytse.evaluate('echo ("*** Here is your variable:" @ $MyVariable);')
[b]#the main loop is broken out and can be combined with other frameworks rather easily[/b]
while pytse.tick():
pass
[b]#cleanup pytse.. goodbye![/b]
pytse.shutdown()-Josh Ritter
Prairie Games, Inc
#82
this is really cool and I'm seriously considering to switch from TorqueScript to Stackless Python.
There is still one thing I am unsure of... the callback method in the example is OnMyButton, which is one global function. Is that how you would approach defining new functions in Python or is there a cleaner way, like keeping them in a class or something? The code would get very messy if you implement all functions for all objects like that(MonsterOnCollision, PlayerOnCollision, PlayerFireWeapon...). And do you have to export those functions for all objects you create or do you export them once for an object type?
Any clarification on this is very appreciated. :)
08/07/2006 (4:44 am)
Hey Josh,this is really cool and I'm seriously considering to switch from TorqueScript to Stackless Python.
There is still one thing I am unsure of... the callback method in the example is OnMyButton, which is one global function. Is that how you would approach defining new functions in Python or is there a cleaner way, like keeping them in a class or something? The code would get very messy if you implement all functions for all objects like that(MonsterOnCollision, PlayerOnCollision, PlayerFireWeapon...). And do you have to export those functions for all objects you create or do you export them once for an object type?
Any clarification on this is very appreciated. :)
#83
And I ran into a problem compiling TGE as a DLL... I made all changes in the diff and added the pytse source file to my project(Visual C++ 2005 btw). I changed the build method to DLL, made sure it is multi-threaded debug, built, named the DLL to pytse.pyd and copied it to the game directory. However, if I want to start the engine with python.exe I get the following error:
"Error, a DecalManager(some value) isn't properly out of the bins!"
I'm pretty unsure what this means, I guess a null-pointer or some other memory related problem...
Is there anyone who might know what I am doing wrong?
08/08/2006 (1:12 am)
Anyone? :/And I ran into a problem compiling TGE as a DLL... I made all changes in the diff and added the pytse source file to my project(Visual C++ 2005 btw). I changed the build method to DLL, made sure it is multi-threaded debug, built, named the DLL to pytse.pyd and copied it to the game directory. However, if I want to start the engine with python.exe I get the following error:
"Error, a DecalManager(some value) isn't properly out of the bins!"
I'm pretty unsure what this means, I guess a null-pointer or some other memory related problem...
Is there anyone who might know what I am doing wrong?
#84
08/08/2006 (8:57 am)
I'm not sure what that error means, but maybe you should double check that the diffs were applied correctly? If you did it by hand (like me), it can be very easy to make a mistake. That's my best guess, but I'm not very knowledgeable about TGE's inner goings-on.
#85
But it would be nice if someone could reply to my previous question :) I'm still learning Python but if it is not possible to solve that ugly problem I guess I will just stop... I know the benefits of Stackless, I am just unsure if it is possible to solve that stuff...
And another question arised... is it possible to make this compile for a dedicated linux server? I kept trying to make pytse independent of the WinAPI... the code works under Windows but I get segfaults under Linux. :/ Anyone succeeded to get this to run under Linux?
08/08/2006 (12:04 pm)
Nevermind, I just did something really stupid. ;DBut it would be nice if someone could reply to my previous question :) I'm still learning Python but if it is not possible to solve that ugly problem I guess I will just stop... I know the benefits of Stackless, I am just unsure if it is possible to solve that stuff...
And another question arised... is it possible to make this compile for a dedicated linux server? I kept trying to make pytse independent of the WinAPI... the code works under Windows but I get segfaults under Linux. :/ Anyone succeeded to get this to run under Linux?
#86
08/12/2006 (1:50 am)
Uh, nevermind.. I got everything sorted out eventually in exchange for some hair. :D
#87
Where self.resetCanvas is a member function of my Client class. Doesn't this effectively export the function to the console, allowing it to be accessed from anywhere? I keep getting a ' (0): Unable to find function resetCanvas' error, which is a bit confusing.
08/14/2006 (12:44 am)
I don't seem to be completely clear on how the export() function works. I am attempting the following:pytse.export(self.resetCanvas, "", "resetCanvas", "Redraws the game canvas", 2, 2)
Where self.resetCanvas is a member function of my Client class. Doesn't this effectively export the function to the console, allowing it to be accessed from anywhere? I keep getting a ' (0): Unable to find function resetCanvas' error, which is a bit confusing.
#88
I know you are probably very busy and I hope I'm not getting on your nerves but would you mind sharing how you made Twisted and Python work together?
I don't know if it is any good but I wrote a new Reactor for Twisted, that is tickable just like your Torque module, so I can run both event loops in their own tasklets.
Is there a better way to make them play nicely together? Scheduling a torque tick every so often using Twisted looks a bit messy to me and that was the only other option I saw...
08/14/2006 (1:09 am)
@Josh Ritter:I know you are probably very busy and I hope I'm not getting on your nerves but would you mind sharing how you made Twisted and Python work together?
I don't know if it is any good but I wrote a new Reactor for Twisted, that is tickable just like your Torque module, so I can run both event loops in their own tasklets.
Is there a better way to make them play nicely together? Scheduling a torque tick every so often using Twisted looks a bit messy to me and that was the only other option I saw...
#89
08/14/2006 (7:01 am)
@Brian: For global (ie no namespace) functions, leave out the namespace parameter completely instead of using an empty string. Ie:pytse.export(self.resetCanvas, "resetCanvas", "Redraws the game canvas", 2, 2)
#90
and then in main.cs:
This code was written when I was still embedding Python into TGE. Once you start using Torque as a Python module, it probably makes more sense to derive a new reactor as you are doing. Though, either method will work :)
-JR
08/14/2006 (9:46 am)
For our last game I wrote the following:from mud.tgepython.console import *
from twisted.internet import reactor
def ReactorTick():
if reactor.running:
reactor.runUntilCurrent()
reactor.doIteration(0)
def ReactorStart():
reactor.startRunning()
def ReactorStop():
reactor.stop()
while reactor.running:
ReactorTick()
TGEExport(ReactorTick,"Py","ReactorTick","desc",1,1)
TGEExport(ReactorStart,"Py","ReactorStart","desc",1,1)
TGEExport(ReactorStop,"Py","ReactorStop","desc",1,1)and then in main.cs:
//Twisted reactor
function tickReactor()
{
Py::ReactorTick();
schedule(10, 0, tickReactor );
}
function startReactor()
{
Py::ReactorStart();
schedule(10, 0, tickReactor );
}
function onStart()
{
// Default startup function
startReactor();
}This code was written when I was still embedding Python into TGE. Once you start using Torque as a Python module, it probably makes more sense to derive a new reactor as you are doing. Though, either method will work :)
-JR
#91
It's good to know that I'm on the right track... I still have to get used to the idea of having multiple main loops run concurrently but I like what you can do thus far. :) Stackless is cool and Twisted is just a blast to work with.
08/14/2006 (12:25 pm)
Wow, thanks for the quick response, I really appreciate that. :)It's good to know that I'm on the right track... I still have to get used to the idea of having multiple main loops run concurrently but I like what you can do thus far. :) Stackless is cool and Twisted is just a blast to work with.
#92
08/21/2006 (1:02 pm)
Microsoft's IronPython sure is looking mighty tasty with the announcement of TorqueX! Basically, you'll have full access to the public interface in Python :)
#93
08/21/2006 (5:08 pm)
Josh - yeah. TorqueX opens up an entirely new realm of possibilities for people like me. Being able to use the CLR to code entirely in Python is a dream come true. :)
#95
TGB works great, but TGE doesn't seem to like it for some reason.
01/07/2007 (10:40 am)
Has anyone had any issue porting this to TGE 1.4.2?TGB works great, but TGE doesn't seem to like it for some reason.
#96
02/07/2007 (11:05 am)
Does anyone have a ready made patch for TGE 1.5 for use in linux?
#97
Error, a DecalManager (1ac9c90) isn't properly out of the bins!
Error, a afxResidueMgr (1aca360) isn't properly out of the bins!
Thanks much if anyone can help.
02/11/2007 (10:48 pm)
Has anyone tried to get this to work with a TGE 1.5 + AFX build? I made all the changes in the source that was specified in the supplied .diff, and it compiled fine as a Multi threadded .DLL. When I went to launch it via the sample script, I would get the following two errors in my console log:Error, a DecalManager (1ac9c90) isn't properly out of the bins!
Error, a afxResidueMgr (1aca360) isn't properly out of the bins!
Thanks much if anyone can help.
#98
I'd be really interested to have a reason to use Python more :)
02/13/2007 (2:05 pm)
Does anyone have a rough performance comparison between Python and TorqueScript. Or could they point out the pro's/con's of the methods?I'd be really interested to have a reason to use Python more :)
#99
I'm having trouble separating torque script and Python. I want to do it all one way or the other. Even Prairie Games states that the idea isn't to mix the code, but to do it all Python, which is what I want to do myself.
But in the example Prairie Games used pytse.evaluate() to execute torque script to make 'MyButton'. How come that couldn't be done 100% in Python? Or could it somehow?
02/17/2007 (6:08 pm)
I think this is very vauable and thanks to Prairie Games for sharing this.I'm having trouble separating torque script and Python. I want to do it all one way or the other. Even Prairie Games states that the idea isn't to mix the code, but to do it all Python, which is what I want to do myself.
But in the example Prairie Games used pytse.evaluate() to execute torque script to make 'MyButton'. How come that couldn't be done 100% in Python? Or could it somehow?
#100
02/18/2007 (7:50 am)
@Merfy: GUI and Datablock generation is still done in Torque Script I think. Moving that to Python isn't worth it in my opinion(since you also have to rewrite the editors). If you want to do it from Python though you'd have to write your own functions in C++ and expose them to Python.
Torque Owner SM3
Default Studio Name
@Johan: True, I guess it was a poor choice of words. I'm still amazed at all it does!