call a python function from cpp file?

Talk among developers, and propose and discuss general development planning/tackling/etc... feature in this forum.
Post Reply
dagg
Bounty Hunter
Bounty Hunter
Posts: 138
Joined: Thu May 22, 2008 8:53 am

call a python function from cpp file?

Post by dagg »

is it possible in the game?
iblis
Star Pilot
Star Pilot
Posts: 4
Joined: Mon Dec 29, 2008 4:21 am

Re: call a python function from cpp file?

Post by iblis »

dagg wrote:is it possible in the game?
There's a good example of doing so in src/command.cpp (search for "PyRun_"). I honestly don't know C++, or much about the VS internals, but in C you can do so like this:

Code: Select all

#include <Python.h>

void exec_py(const char* code)
{
  Py_Initialize();
  PyRun_SimpleString(code);
  Py_Finalize();
}
Hope this helps.
dagg
Bounty Hunter
Bounty Hunter
Posts: 138
Joined: Thu May 22, 2008 8:53 am

Re: call a python function from cpp file?

Post by dagg »

wow, cool, if it is right, you've solved me huge headache :)
dagg
Bounty Hunter
Bounty Hunter
Posts: 138
Joined: Thu May 22, 2008 8:53 am

Re: call a python function from cpp file?

Post by dagg »

there is the LoadAIScript function, question is how to call a function from the loaded file
ace123
Lead Network Developer
Lead Network Developer
Posts: 2560
Joined: Sun Jan 12, 2003 9:13 am
Location: Palo Alto CA
Contact:

Re: call a python function from cpp file?

Post by ace123 »

I think LoadAIScript attaches a pythons script to a unit file. And I believe an AI script is basically a class with an Execute() function that gets run every frame.
PyRun_SimpleString is really slow if you do it every frame since it has to parse and compile the string each time, but it's fine for UI functions that happen at most a few times per second.

If you want something every frame, much better is to interact with python directly:

Code: Select all

PyObject *module = PyImport_AddModule(modname);
if (module) {
    PyObject *dict = PyModule_GetDict(module);
    if (dict) {
        PyObject *func = PyDict_GetItemString(global_dict, func_name);
        if (func) {
            PyObject_CallObject(func, NULL);
        }
    }
}
Also, you are not supposed to call Py_Initialize/Finalize unless you are making a standalone app. Boost already initializes the python interpreter.
dagg
Bounty Hunter
Bounty Hunter
Posts: 138
Joined: Thu May 22, 2008 8:53 am

Re: call a python function from cpp file?

Post by dagg »

thanks, what will help me :)
dagg
Bounty Hunter
Bounty Hunter
Posts: 138
Joined: Thu May 22, 2008 8:53 am

Re: call a python function from cpp file?

Post by dagg »

what is modname var? the python file?
also global_dict, what is it?
I don't see a way how the object will attach to a unit
what about function parameters? I guess passing self is unneeded.
ace123
Lead Network Developer
Lead Network Developer
Posts: 2560
Joined: Sun Jan 12, 2003 9:13 am
Location: Palo Alto CA
Contact:

Re: call a python function from cpp file?

Post by ace123 »

Here's a simple function you can try

Code: Select all

// If you need to pass arguments, pass in a tuple created using PyTuple_New
PyObject *callPythonFunction(char *modname, char *funcname, PyObject *args=NULL) {
    PyObject *returned = NULL;
    PyObject *module = PyImport_AddModule(modname); // without .py extension--this is the same as typing "import mission_lib" in python.
    if (module) {
        PyObject *dict = PyModule_GetDict(module); // Takes an imported module and returns its dictionary
        PyObject *func = PyDict_GetItemString(dict, funcname);
        if (func && PyCallable_Check(func)) {
            returned = PyObject_CallObject(func, args);
        }
        Py_DECREF(module);
    }
    return returned;
}
Then, you can do something like:

Code: Select all

PyObject *returned = callPythonFunction("mission_lib", "PickRandomMission");
if (returned) {
    // do something with the return value.
    Py_DECREF(returned);
}
dagg
Bounty Hunter
Bounty Hunter
Posts: 138
Joined: Thu May 22, 2008 8:53 am

Re: call a python function from cpp file?

Post by dagg »

cool, thanks for the example
dagg
Bounty Hunter
Bounty Hunter
Posts: 138
Joined: Thu May 22, 2008 8:53 am

Re: call a python function from cpp file?

Post by dagg »

quick question, if I have a python class that I want to use, will this:

Code: Select all

PyObject *module = PyImport_AddModule(modname); // without .py extension--this is the same as typing "import mission_lib" in p
instantiate it? e.g. call the __init__ function?
ace123
Lead Network Developer
Lead Network Developer
Posts: 2560
Joined: Sun Jan 12, 2003 9:13 am
Location: Palo Alto CA
Contact:

Re: call a python function from cpp file?

Post by ace123 »

Classes and functions are the same thing in Python. That's the wonderful thing about "duck typing".

For example, doing callPythonFunction("mission_lib", "MyClass") will instantiate a new MyClass, the same as typing "MyClass()" in python.

The return value should just be a new instance of the object. If you want to pass arguments, you will have to make them into a tuple using the PyTuple_* set of functions.
dagg
Bounty Hunter
Bounty Hunter
Posts: 138
Joined: Thu May 22, 2008 8:53 am

Re: call a python function from cpp file?

Post by dagg »

so for a file name abc with a class named xyz, running module=callPythonFunction("abc", "xyz") will instantiate the class (e.g. run the __init__ function) and the return value will be the object which holds that class and if I want to run a function from that class, all I need to do is this:

Code: Select all

PyObject *dict = PyModule_GetDict(module); // Takes an imported module and returns its dictionary
         PyObject *func = PyDict_GetItemString(dict, funcname);
        if (func && PyCallable_Check(func)) {
            returned = PyObject_CallObject(func, args);
        }
right?
ace123
Lead Network Developer
Lead Network Developer
Posts: 2560
Joined: Sun Jan 12, 2003 9:13 am
Location: Palo Alto CA
Contact:

Re: call a python function from cpp file?

Post by ace123 »

That is basically correct.
I think you have to make sure that you dereference objects at the right times so that they can be garbage collected. The code I pasted in does two Py_decref calls for the module (I think once you are done with calling that function) and returned class once you are done using it (unless you hold onto the reference.

I am curious what you are trying to do with this that can't already be done through other means.

The engine already supports subclassing missions (boost::python makes interacting with python classes very simple), and you can also creating modules/classes that run on each frame, and you can also have code execute when you click on a GUI.
dagg
Bounty Hunter
Bounty Hunter
Posts: 138
Joined: Thu May 22, 2008 8:53 am

Re: call a python function from cpp file?

Post by dagg »

has part of vt mode, I need to add support for more higher speeds (like about ~199000C) and custom distances between systems. current max speed is about 2.4C and the distance between systems is constant and depends on the distance_to_warp value in the config file.
I've wrote 2 python classes which load data from a file where one holds system's coordinates that is a temp file, will change it later to stuniverse.xml (our equivalent to your mickey_way.xml) the other one holds the max values of speed in terms of startrek in which each ship class has it's normal speed, max speed and critical speed so using a getter I can retrieve that ship's relevant data.
now I need to incorporate them into the cpp code (which I'm doing right now)
Post Reply