Discussion:
[C++-sig] Boost.Python As Engine's Scripting Language
Oam
2015-04-28 06:35:33 UTC
Permalink
After further tinkering I'm feeling like I have a good starting location. I
have the BaseBehavior inheritable class exported to the Python side for
utilization, and I have my cpp side calling the particular test script that
contains a class inheriting from the BaseBehavior and executing it.

However, now I am trying to figure out how to collect / extract that
particular class after the script has been executed on the cpp side. This is
what I'm trying to do as a simple example, but I'm not sure how to specify
what the result to look for. All I know is that it inherits from the
BaseBehavior class.
import Engine
print("Hello?")
print("Hello From TestPiece?")
test = TestPiece()
test.OnUpdate()
This is my cpp side locating the "test" object from the main_namespace
BP::dict, which works.
try
{
PyImport_AppendInittab("Engine", &PyInit_Engine);
Py_Initialize();
// '__main__' is the name of the scope in which top-level code
executes
BP::object main_module = BP::import("__main__");
// we create a dictionary object for the __main__ module's namespace
// m.x = 1 is equivalent to m.__dict__["x"] = 1
// Special read-only attribute: __dict__ is the modules namespace as a
dictionary object
BP::dict main_namespace = BP::extract
<BP::dict>
(main_module.attr("__dict__"));
auto result = BP::exec_file("../Debug/test.py", main_namespace,
main_namespace);
ME::BaseBehavior& base = BP::extract
&lt;
ME::BaseBehavior&amp;
&gt;
(main_namespace["test"]);
base.OnUpdate();
}
catch (...)
{
PyObject *ptype, *pvalue, *ptraceback;
PyErr_Fetch(&ptype, &pvalue, &ptraceback);
if (pvalue != nullptr)
{
std::string error = BP::extract
<std::string>
(pvalue);
std::cout << error << std::endl;
}
}
How would I make it so it retrieves the TestPiece class for execution
without having to manually create an object on the python side. What I
really want is for the object to exist on the cpp side, but the python side
is what is manipulating it's behavior.



--
View this message in context: http://boost.2283326.n4.nabble.com/Boost-Python-As-Engine-s-Scripting-Language-tp4674850p4674859.html
Sent from the Python - c++-sig mailing list archive at Nabble.com.
Stefan Seefeld
2015-04-28 12:17:00 UTC
Permalink
On 28/04/15 02:35 AM, Oam wrote:

[...]
Post by Oam
How would I make it so it retrieves the TestPiece class for execution
without having to manually create an object on the python side. What I
really want is for the object to exist on the cpp side, but the python
side is what is manipulating it's behavior.
The approach I typically use for this is the same in Python and C++:
After the script has been run, the "main_namespace" dictionary will
contain all the objects (including types) that the script added. Thus
it's possible to iterate over all the content and look for types that
are derived classes of "MagicEngine.BaseBehavior". Once you have those
you may instantiate objects of those types and operate on them in your
main application's runtime.
In that sense the python script really becomes a configuration file
rather than an executable script.

Stefan
--
...ich hab' noch einen Koffer in Berlin...
Ger van Diepen
2015-04-28 13:07:06 UTC
Permalink
I believe we have done something similar to what you intend to do.

We have an astronomical query language (implemented in C++) where
arbitrary user defined functions (named libname.func) can be loaded
dynamically from a shared library. It has the possibility of user
defined functions implemented in Python. In the query language such
functions are named py.module.func. Each such function has to reside in
a class 'func', subclassed from a UDFBase class (basically implemented
in C++ and wrapped using Boost-Python). It makes it possible for the
Python code to call back to the C++ code (e.g. to get the value of the
function arguments).
Basically the 'func' class must have a function 'setup' (to check the
argument data types, etc.) and a function 'get' to obtain query results.
These functions are called from C++ using the boost::object::attr
function.
Clearly, such functions will perform far from optimal, but it is very
convenient for special ad-hoc query functions.

If you like to, I can send you more details about the implementation.

Cheers,
Ger
(Original Message Posted At :
http://www.gamedev.net/topic/667952-boostpython-as-engines-scripting-language/
<http://www.gamedev.net/topic/667952-boostpython-as-engines-scripting-language/>
)

Am I thinking about this the right way?

I'm currently working with some Boost and Boost.Python in my C++
project, in
attempts to get my project's library to utilize Python as it's game
scripting language. Similarly I suppose to how Unity utilizes C# as one
of
it's game scripting languages.

So let's say I have an abstract class that contains the virtual methods
for
overriding the specific behaviors of each particular event, such as
Unity's
MonoBehavior, but BaseBehavior in my case.

This is what I'm trying to do and what I'm thinking the right way to do
this
is :

1) I have a project that is dedicated to just the library portion
of the
framework (Contains the BaseBehavior abstract class)

class BaseBehavior()
{
public:
virtual void OnUpdate() = 0;
};

2) Export this library portion classes / functions / etc using
Boost.Python

class BaseBehaviorWrap : public BaseBehavior, public
boost::python::wrapper<BaseBehavior>
{
public:
void OnUpdate()
{
this->get_override("OnUpdate")();
}
};

BOOST_PYTHON_MODULE(ModuleName)
{
boost::python::class_<BaseBehaviorWrap,
boost::noncopyable>("BaseBehavior")
.def("OnUpdate",
boost::python::pure_virtual(&BaseBehavior::OnUpdate));
}

3) Within Python, in for example: ObjectBehavior.py I import my
library
module inheriting from a new class from the BaseBehavior and utilizing
the
particular override behaviors, such as OnUpdate()

import ModuleName

class NewObjectBehavior(BaseBehavior):
def OnUpdate(self):
# Game Behavior
# ...

4) Back within the C++ side I'll have a list/vector of all the
objects
that contain scriptable behavior and their associated attached scripts
that
contain this BaseBehavior script
5) I'll collect each script per object and call the [ object
exec_file(str filename, object globals = object(), object locals =
object())
] function within the Boost.Python on my C++ engine side
6) From here I will utilize the boost::python::extract object to
collect
my particular overridden functions and call them accordingly per
object

I'm concerned with my fascination to go back to the C++ side to execute
each
file and then extract each function I need per object that contains
behavior. Is this the right way to do this, or should everything be
done on
the Python side? I'm really trying to keep the ideal that the GameApp
is
utilized within C++, such as the window creation, event handling,
frame
calculations, etc, just the engine specific pieces. While the Python
side is
dedicated specifically to just Game Behaviors.



--
View this message in context:
http://boost.2283326.n4.nabble.com/Boost-Python-As-Engine-s-Scripting-Language-tp4674850.html
Sent from the Python - c++-sig mailing list archive at Nabble.com.
Loading...