Boost.Python As Engine's Scripting Language

Next Topic
 
classic Classic list List threaded Threaded
2 messages Options
Oam
Reply | Threaded
Open this post in threaded view
|

Boost.Python As Engine's Scripting Language

Oam
This post has NOT been accepted by the mailing list yet.
This post was updated on .
(Original Message Posted At : 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 class)
       
        class BaseBehavior()
        {
          public:
            virtual void OnUpdate() {};  
        };
    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 parent class
    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.
Oam
Reply | Threaded
Open this post in threaded view
|

Re: Boost.Python As Engine's Scripting Language

Oam
This post has NOT been accepted by the mailing list yet.
This post was updated on .
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.

This is my test.py script:
import Engine

print("Hello?")

class TestPiece(MagicEngine.BaseBehavior):
  def OnUpdate(self):
    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<ME::BaseBehavior&>(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 on the cpp side, without having to manually create an object on the python side for the system to know what to search for? Upon further thought, I definitely do need a way to associate the script to a particular object such as it searching for the initial "test" object with the BP::dict object, I just need a way for the system to be able to identify all those objects, creating the initial object at the end of the python file doesn't seem right.