Adding Python

Adding a dynamic scripting language to a game allows for rapid changing of game elements and also allows the community to change and expand the game it self. There are many scripting languages to choose from so why python? Compared to other scripting languages python offers a relatively simple syntax, dynamic typing, vast standard libraries, easy to interface with c/c++ via boost.python and a lot of documentation and tutorials. However python does have a few set backs. Its very hard to sandbox python thus it can open up alot of exploits to server operators and there is some complexities that the programmers have to deal with (but this is better than having the end user deal with other complexities that python removes).

Adding Python to Source the source engine from scratch is a major task as there is alot of work involved in getting all the different components running. However the GoldenEye Source Team has all ready done the majority of this work so that other teams can easily integrate python in a matter of minutes.

Python Manager

In your Half-Life 2 SDK Solution, add these two files to your server project (make a new folder called python):

ge_pymodules.cpp
ge_pymanager.cpp
ge_pymanager.h

These files define the python manager class (PMC). The PMC enables you to have different instances of python running for different tasks. Each instance has its own dictionary that contains the global defines and local defines and so that two instances cant impeded on each other. PMC also loads the setup scripts that redirect python io to the console and set up the root python path so it knows where to load python files from. The PMC also includes a concommand py that enables you to execute python code in the global python instance (support for other instances coming soon)

Please note: that each python instance is executed in the same python engine and thus should be only used in the same thread (not an issue for source).

Init Python

Once that is done you will need to make sure your game code calls the init and shutdown functions. In gameinterface.cpp add this into DLLInit before the return true statement (around line 550):

PythonInit();

And in the DLLShutdown function add this:

PythonShutdown();

Also add this after the defines up the top:

externvoid PythonInit();externvoid PythonShutdown();

Note: The reason we extern this instead of include a header file is to keep the python aware code separate from the source sdk code.

The last thing to do is to call InitHandles (GoldenEye Source does this in GameRules but it can be any where you want). Add this to your game rule constructor:

#ifndef CLIENT_DLL
PythonInitHandles();#endif

And to the deconstructor:

#ifndef CLIENT_DLL
PythonShutdownHandles();#endif

And again we need to extern it up the top of the file:

externvoid PythonInitHandles();externvoid PythonShutdownHandles();

Making Your own Python Instance

Now this is the fun part, making your own python instance. You will need to make your own class that inherets from PyHandle and provides functionality for Init, Shutdown.

Note: An example python handle is provided in the package.

Init

Init gets called after Python gets init and thus provides the best place to load your script.

void MyPyHandle::Init(){
ExecFile("test.py");}

Note: The default python dir is modfiles\scripts\python and can be changed in the python manager

Shutdown

Shutdown handles the shutting down of python handle and should do things in here like call shutdown functions in your script.

UseFull Functions

The Python handle class allows you to exec code as c++ strings by calling Exec and also get the dictionary for use with other Python functions

Creating The Instance

On the top of your new PyHandle class you need to add a function allowing global access to your Python instance. Add something like this:

Exposing C++ Classes/Functions/Globals to Python

This is quite easy and a detailed guide can be found on the boost.python webpage. Once you have your module defined you will need to add it to ge_pymodule.cpp like so:

void RegisterPythonModules(){
REG( HLUtil );//this one is all ready there
REG( MyModule );//this is your new module (change the name to match yours)}

Some interfaces for the Source SDK have all ready been provided (feel free to expand on this as well), you will just need to add them to your project and then include them in the register python modules function.

Notes on compiling python from scratch

bp namespace errors

If you receive an error in ge_pymodules.cpp or elsewhere related to the bp namespace not existing, make sure you include boost/python.hpp, and definition of the namespace, as in ge_pymanager.cpp:

namespace bp = boost::python;

linker issues in Visual C++ 2010

Recompile the boost python libraries from the solution in src\utils\python\boost, though you may need to change the output file paths to match those of the existing boost_pythoncore(_d).lib file.