help on adding networking features. Please help!!

trowa

23-02-2006 09:37:13

Does anybody know how to "combine" Pyogre and Twisted network library into one application?

Or rather how do i use the two so that i can have a server accepting client logins while running the server version of the applicaion?

Please help!!

griminventions

23-02-2006 12:46:50

I haven't used Twisted (yet) but I'd imagine it's a matter of learning how to use Twisted and then figuring out how you want to implement your client-server architecture. There's probably no magic bullet way to connect them that will work universally. Dig in, and learn!! ;)

bigjhnny

14-03-2006 16:56:29

I have actually been trying to do the same thing: integrate twisted with pyogre.

And of course, twisted and pyogre both have their own event loop. I guess there are three options:

1. run pyogre's loop as main loop, and take care of twisted events as they come up

2. run twisted loop as main loop, take care of rendering in twisted's loop

3. run both in two separate threads (implement some way for the two threads to interact with each other....)

I've been looking into the #1 option using the twisted threadedselectreactor. But not having much success. Ogre's main loop seems to want to run as fast as it can.... :) (anyone has done this? offer any hint?)

So, now I'm looking into #2. Basically, I'm wondering if there is a way to manual step through the ogre's loop. Thus, I make twisted call ogre as often as it can, etc....

#3, I'm still reserving it for my last desperate attempt.

Any comments?

bigjhnny

14-03-2006 19:46:10

Answering my own post....

Seems like #2 is the way to go. Just discovered the goodness of ogre's renderOneFrame.

Oh and Thanks Jason for the sample testApp without ExampleFramework!

Although, I'm still curious about #3 option though. Seems interesting....

pkdawson

15-03-2006 06:03:49

Although, I'm still curious about #3 option though. Seems interesting....

Well, there's a reason most games aren't multi-threaded. Going for option #3, with two threads and all the necessary synchronization between them, would give you pretty much the exact same result as a well-designed single thread, but with the added overhead of more code and CPU cycles needed to handle the thread switching and synchronization.

I haven't used Twisted, but I assume you're polling for network events, handling them (if any), then rendering the result. It doesn't get much faster or simpler than that.

bigjhnny

15-03-2006 07:49:59

What I'm doing is fire up a task that runs as fast as possible from twisted.inernet.task module:

l = task.LoopingCall(self.app.render)
l.start(0)


And the app.render would basically call root.renderOneFrame....

I was still able to use frame listeners and all that.
I think the default twisted reactor is "select" based, instead of "poll" based. That said, I am using the twisted.spread.pb (perspective broker) to distribute all my game objects across server/client.

And you are absolutely right, when I got it to work, I was like: :twisted: It doesn't get easier.

One thing to note though, as I run the render loop within a twisted task, the frame rates seem to have dropped quite bit... I'm getting 100 fps on a robot and a 3500 x 3500 plane with texture.... where I think I used to get 300+....

Well, we'll see.

pkdawson

15-03-2006 18:38:08

I think the default twisted reactor is "select" based, instead of "poll" based.

One thing to note though, as I run the render loop within a twisted task, the frame rates seem to have dropped quite bit... I'm getting 100 fps on a robot and a 3500 x 3500 plane with texture.... where I think I used to get 300+....


Look into that. If you set the timeout for a select() call to zero, it's the equivalent of polling. If it's not zero, then select() will sit around waiting for an interrupt, which is great for a web server, but not good when you could be rendering!

I looked into the internals of Twisted, and it's pretty complex. From what I can see, you might want to override the doSelect() method of a SelectReactor class, then call the parent's doSelect() with a timeout of 0.

eg,

class MySelectReactor(SelectReactor):
def doSelect(self, timeout, reads, writes):
print "old timeout =", timeout
SelectReactor.doSelect(self, 0, reads, writes)


Something like that *should* work.

bigjhnny

16-03-2006 01:32:11

I think it's not running the "doSelect" or the "doIterate" for some reason:


from twisted.internet.selectreactor import SelectReactor


class myReactor(SelectReactor):
def doSelect(self, timeout, reads, writes):
print timeout

def doIterate(self, timeout, reads, writes):
print timeout

myreactor = myReactor()
def bla():
print '1234'

myreactor.callLater(2, bla)
myreactor.callLater(4, lambda: myreactor.stop())
myreactor.run()


Any ideas? I'm gonna look into it too, just wanted to post this.

pkdawson

16-03-2006 04:48:34

Okay, try overriding doIteration with only two params.
def doIteration(self, timeout):
print timeout
SelectReactor.doIteration(self, timeout)


If you do it like that, it's pretty slow. Changing it to
def doIteration(self, timeout):
print timeout
SelectReactor.doIteration(self, 0)

makes it much faster, as I expected. Or, you can override the timeout method, which seems to only get called by the mainLoop.

def timeout(self):
return 0


Hope that helps.

bigjhnny

16-03-2006 08:44:56

Hm.. I didn't get it to work. Here is a little test script to illustrate what I did. It prints out "foo" immediately and just sits there....


# server.py
from twisted.internet.selectreactor import SelectReactor
from twisted.internet import task

class myReactor(SelectReactor):
def doIteration(self, timeout):
SelectReactor.doIteration(self, 0)

reactor = myReactor()

def foo():
print 'foo'

l = task.LoopingCall(foo)
l.start(1) # run every second
reactor.run()


but then even if i do this:

class myReactor(SelectReactor):
def doIteration(self, timeout):
SelectReactor.doIteration(self, timeout)


It still wouldn't work.

Must be something odd I'm doing....

bigjhnny

16-03-2006 18:51:06

Cool...

I think this works... (kinda hacky),but then I looked at task module and it said API unstable...

# server.py
import sys
from twisted.internet.selectreactor import SelectReactor
from twisted.internet.main import installReactor

class myReactor(SelectReactor):
def doIteration(self, timeout):
# print timeout
SelectReactor.doIteration(self, 0)

reactor = myReactor()
installReactor(reactor)

def foo():
print 'foo'

from twisted.internet import task
l = task.LoopingCall(foo)
l.start(1)
reactor.run()


Or the callLater(0, func) also worked replacing the loopingcall. I'll try this on my game when I get home tonight :D. Will let you know the performance diff results.

[edit]: the trick was to import task after the reactor gets installed....

Thanks a bunch man!

bigjhnny

17-03-2006 01:19:58

It's odd. I'm getting the same frame rates.

From the printed timeouts, once the rendering starts, the timeouts passed to the function: doIteration are all "0"s.

I think this is dictated by the fact that I'm doing a "0" delay twisted.internet.task.

So the problem is not there.. :shock:

pkdawson

17-03-2006 05:01:11

Hmm, I was afraid of that. My suggestion would be to fire up the profiler and see which functions are using up the most time.

You might want to toss out Twisted's loop and call doIteration() yourself, unless you're making use of other delayed calls. The Reactor loops seems to do this:
self.runUntilCurrent()
t2 = self.timeout()
t = self.running and t2
self.doIteration(t)


I suspect runUntilCurrent might be the problem. You could try something like:
reactor.runUntilCurrent()
reactor.doIteration(0)
self.root.renderOneFrame()


Or just:
reactor.doIteration(0)
self.root.renderOneFrame()


I don't know if Twisted uses delayed calls internally. If it doesn't, you probably don't need runUntilCurrent.

I assume you're already using psyco. If this doesn't work, give the profiler a shot. The problem might simply be that Twisted is eating up too much CPU time. You could use a timer and call doIteration() only once every 100ms or so, rather than once every frame. At 300fps, polling for network events every 3ms is overkill.

bigjhnny

18-03-2006 02:59:03

:oops:

Ok looks like the frame rates reduction was due more to me turning on shadows and forgot to turn it back off. That with twisted running compared to the demo is where the difference is.

With what I have (simple scene with robot, plane textured, no shadows, walking animation on), the difference between running twisted or not is:

200 vs 180.

When having shadows on, the numbers is like:

100 vs 99.

So that isn't bad. So I'd say that's acceptable for now.

BerndWill

17-04-2006 20:31:00

Hi,

could one of you guys please post an example including PyOgre main loop example displaying some media object or so and twisted loop integrated in one main application loop ?

Thank you very much in advance
Bernd