userExit without kill the python interpreter

Hello,

I have a problem: I develop a racing game and I use Panda3D and JPype (allows you to use java in python).

I have two GUI written in Java --> One for the server and another for the client. These two GUI communicate with Java RMI.

it works well.

With JPype, I create the client GUI
With Java, I start the serveur GUI.

it works well.

with the client application (python + JPype), I use Panda3D for showing the game. For this I create a python class (Game) who inherit of ShowBase and after I call the run method of Game.

Again, it works well.

But now I want, with the server , restart the game.
For that I need to destroy all of the Panda3D objects. I see it exist a function named userExit() in Showbase. I have try to call it in a Panda3D task (because it’s impossible to run code after the run function) This is ok but this function kill the python Interpreter and of course the client GUI. I don’t want to kill the client GUI but I don’t know how do this.

Can you help me?

Thanks in advance.

Bye

Hmm, there would be several ways to catch termination of the Python interpreter.

1.) Since you already derive your class Game from ShowBase: override the method “userExit”, since this calls “self.finalizeExit()”, which in turn calls “sys.exit()” which stops the interpreter.

2.) Let ShowBase call sys.exit(), and catch the event by doing something like this:

try:
  Game.run()
except SystemExit as e:
  # handle the system exit

Anyway, I don’t think this will get you any further. Why actually is the main window closed? I assume the Java GUI is still open at this time (and running it’s own main loop?). Or will both GUIs ( Java and Panda3D) close at the same time? Maybe you should consider IPC, that is a Python + Jython/Java process for the Java-UI, and one for the Panda3D window.

If it is just a “restart” of the game in the sense of “a new race is starting” then it would be better to clean up the Panda3D scene graph properly and not close/reopen any windows.

This is just a restart of the game but a lot of informations are send to the client when the game is restarting.

Panda3D do all treatment for the game (keyboard, sound, create the road, move the cars, load tree, skybox,add animals, etc…)

this is hard to clean all.

I have try your code but, for me, the print(“stop”) is never call (even calling sys.exit () or base.exitfunc ()):

try:
  Game.run()
except SystemExit as e:
  print("stop")

I just need this!

Wait, you want to clean up all of the Panda objects, without exiting Python? This is indeed difficult to do automatically.

The only way to do this reliably is to write your code so that you keep track of the Panda objects you create, and you are responsible for cleaning up each one of them.

If you want to do this automatically, you really have to exit the Python interpreter and restart it.

David

@drwr
Why not traversing the top nodes or flatten strong and remove only the top nodes then?

That’s assuming the only things you want to remove are nodes. What about intervals, tasks, event hooks, or whatever other non-node objects you might have created?

In fact, removing nodes is not the problem. You generally don’t have to do anything at all to remove the nodes; just detach the parent node and all of the children are automatically cleaned up.

But the OP seems to be asking about how to restore his program automatically to the initial state, and there’s no way that Panda can do that sort of thing for you automatically without knowing all sorts of intimate details about your program and what you’ve done.

david

Silly me. I didn’t consider this.
Speaking about children being cleaned up. Let’s say I’d call removeNode8) on render and replace it with a fresh NodePath. Would that automatically push all nodes (models, textures, states etc.) attached to render to the garbage collector?

And to come back to topic, to clean up everything you’d have to either keep track of all the modifications or at least know where they can be removed. Cleaning up all TaskManagers from Tasks and all Messengers/Directobjects from event listeners would probably already do most of the job.
The whole issue requires perfect OOP and good management.

I got curious. I think I’ll try to do a small demo myself :slight_smile:

Just got an other idea:

start.py

import subprocess

s = 13
first = True
while s == 13:
    if not first:
        print "program restarted"
        first = False
    s = subprocess.call(['./yourapp.py'])

print "Program Exit"

yourapp.py:

import sys
from direct.showbase.ShowBase import ShowBase


class MyGame(ShowBase):
    def __init__(self):
        ShowBase.__init__(self)
        self.simpleModel()
        self.accept("q", self.restartPanda)

    def simpleModel(self):
        smiley = self.loader.loadModel("smiley")
        smiley.reparentTo(self.render)
        smiley.setY(20)

    def restartPanda(self):
        print "trying to restart"
        sys.exit(13)

if __name__ == "__main__":
    mg = MyGame()
    mg.run()

Works like a charm for me. and the problem that name always will be “main” this way can be fixed by expecting a special command line argument in yourapp.py, which the start script parses to it. This prevents accidental start of the yourapp.py script first.

If you need to pass something to the newly started process, you can do so by using a file as a pipe. E.g.:

  1. look if file exists and load if so.
  2. save needed infos into the file so that the next process gets it

Also if you set up the start.py to communicate with the server as well, you can so even control the python subprocess in realtime.

This is not quite right. Panda still listens to events and does everything you tell it beforehand. You can execute code after a period of time, after a key press or after any other specific event. The code that needs to be executed also can come over a socket, file or whatever.