Adding Python: Difference between revisions

From Valve Developer Community
Jump to navigation Jump to search
No edit summary
m (Nesciuse moved page Adding Python/en to Adding Python without leaving a redirect: Move en subpage to basepage)
 
(40 intermediate revisions by 13 users not shown)
Line 1: Line 1:
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).
{{LanguageBar}}


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 itself. 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 a lot 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 [[Wikipedia:Python|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 [http://goldeneyesource.net 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.
 
Adding [[Wikipedia:Python|Python]] to Source the source engine from scratch is a major task as there is a lot of work involved in getting all the different components running. However the [http://goldeneyesource.net GoldenEye Source Team] has already done the majority of this work so that other teams can easily integrate python in a matter of minutes.




== Needed Files ==
== Needed Files ==
 
You will need to check out the code using svn from: http://code.google.com/p/sourcesdkpython/source/checkout (Alternative: https://github.com/Sandern/py-source-sdk-2013) And then export it into your mod.
Download load the python package from [Add url here].
 
Note: Only the windows libraries have been compiled so far. Linux ones will come soon.
 


== First Steps ==  
== First Steps ==  
Line 16: Line 14:
Once you have downloaded the package above extract the folders in the src folder into your root source folder and the folders in the mod folder into your root mod folder.
Once you have downloaded the package above extract the folders in the src folder into your root source folder and the folders in the mod folder into your root mod folder.


In the server project settings you need to:
In the server project settings you need to add some settings so it compile correctly. You will need to add theses to both release and debug unless other wise stated.


Add these to the preprocesser: Configure properties -> c++ -> General-> Additional Include Directories
Add these to: Configure properties -> c++ -> General-> Additional Include Directories
<pre>
<pre>
..\public\python
..\..\public\python
.\server\py
</pre>
</pre>


Add these to the preprocesser: Configure properties -> c++ -> Preprocesser -> Preprocesser defines
Add these to: Configure properties -> c++ -> Preprocesser -> Preprocesser defines
<pre>
<pre>
For Both release and debug:
Py_NO_ENABLE_SHARED
Py_NO_ENABLE_SHARED
BOOST_PYTHON_STATIC_LIB
BOOST_PYTHON_STATIC_LIB
BOOST_ALL_NO_LIB
BOOST_PYTHON_SOURCE
BOOST_PYTHON_SOURCE
BOOST_PYTHON_NO_LIB
BOOST_PYTHON_NO_LIB
For debug only:
Py_DEBUG
</pre>
</pre>


Add this to the linker: Configure properties -> Linker -> General -> Additional Library Directories
Add this to: Configure properties -> Linker -> General -> Additional Library Directories
<pre>
<pre>
..\lib\python
..\..\lib\python
</pre>
</pre>


Add these to the linker: Configure properties -> Linker -> Input -> Additional Dependencies
Add these to: Configure properties -> Linker -> Input -> Additional Dependencies
<pre>
<pre>
boost_pythoncore_d.lib
For release build:
pythoncore_d.lib
boost_pythoncore.lib
pythoncore.lib
 
For Debug build:
boost_pythoncore_d.lib
pythoncore_d.lib
</pre>
</pre>


== Python Manager ==
== Python Manager ==


In your halflife 2 sdk solution add these two files to your server project (make a new folder called python):
In your Half-Life 2 SDK Solution, add these two files to your server project (make a new folder called ''python''):
<pre>
<pre>
ge_pymodules.cpp
ge_pymodules.cpp
Line 52: Line 59:
</pre>
</pre>


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 allows 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)
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)




Line 59: Line 66:
== Init Python ==  
== 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 700):
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):


<source lang=cpp>
<source lang=cpp>
Line 68: Line 75:


<source lang=cpp>
<source lang=cpp>
#ifdef GE_LUA
PythonShutdown();
PythonShutdown();
#endif
</source>
</source>


Line 83: Line 88:




The last thing to do is to call InitHandles and GoldenEye Source does this in GameRules but it can be any where you want. Add this to your game rule constructor:
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:
<source lang=cpp>
<source lang=cpp>
Line 107: Line 112:
== Making Your own Python Instance ==
== Making Your own Python Instance ==


Now this is the fun part, making your own lua instance. You will need to make your own class that inherets from PyHandle and provides functionality for Init, Shutdown.
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.
Note: An example python handle is provided in the package.
Line 113: Line 118:
=== Init ===
=== Init ===


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


<source lang=cpp>
<source lang=cpp>
void MyLuaHandle::Init()
void MyPyHandle::Init()
{
{
ExecFile("test.py");
ExecFile("test.py");
Line 122: Line 127:
</source>
</source>


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


=== Shutdown ===
=== Shutdown ===
Line 130: Line 136:


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
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 ==
== Creating The Instance ==


On the top of your new PyHandle class you need to add a function allowing global access to your Lua instance. Add something like this:
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:


<source lang=cpp>
<source lang=cpp>
Line 162: Line 167:
//other stuff here
//other stuff here


// Start our LUA GamePlay Engine
// Start our Python Handle
if (!GetPyHandle())
if (!GetPyHandle())
new MyPyHandle();
new MyPyHandle();
}
}
</source>
</source>


== Exposing C++ Classes/Functions/Globals to Python ==
== Exposing C++ Classes/Functions/Globals to Python ==
Line 176: Line 180:
void RegisterPythonModules()
void RegisterPythonModules()
{
{
REG( HLUtil );  //this one is all ready there
REG( HLUtil );  //this one is already there
REG( MyModule ); //this is your new module (change the name to match yours)
REG( MyModule ); //this is your new module (change the name to match yours)
}
}
</source>
</source>


Some interfaces for the [[:Category:HalfLife_SDK_Python_Interface|Source SDK have all ready been provided]], you will just need to add them to your project and then include them in the register python modules function.
Some interfaces for the [[:Category:HalfLife_SDK_Python_Interface|Source SDK have already 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 ==
== Notes on compiling python from scratch ==


todo
=== 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:


<source lang=cpp>
namespace bp = boost::python;
</source>


[[Category:Programming]]
=== linker issues in Visual C++ 2010 ===
[[Category:Free source code]]
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.
[[Category:Python]]
{{todo|more}}

Latest revision as of 04:00, 12 July 2024

English (en)Deutsch (de)Русский (ru)Translate (Translate)

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 itself. 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 a lot 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 a lot of work involved in getting all the different components running. However the GoldenEye Source Team has already done the majority of this work so that other teams can easily integrate python in a matter of minutes.


Needed Files

You will need to check out the code using svn from: http://code.google.com/p/sourcesdkpython/source/checkout (Alternative: https://github.com/Sandern/py-source-sdk-2013) And then export it into your mod.

First Steps

Once you have downloaded the package above extract the folders in the src folder into your root source folder and the folders in the mod folder into your root mod folder.

In the server project settings you need to add some settings so it compile correctly. You will need to add theses to both release and debug unless other wise stated.

Add these to: Configure properties -> c++ -> General-> Additional Include Directories

..\..\public\python
.\server\py

Add these to: Configure properties -> c++ -> Preprocesser -> Preprocesser defines

For Both release and debug:
Py_NO_ENABLE_SHARED
BOOST_PYTHON_STATIC_LIB
BOOST_PYTHON_SOURCE
BOOST_PYTHON_NO_LIB

For debug only:
Py_DEBUG

Add this to: Configure properties -> Linker -> General -> Additional Library Directories

..\..\lib\python

Add these to: Configure properties -> Linker -> Input -> Additional Dependencies

For release build:
	boost_pythoncore.lib
	pythoncore.lib

For Debug build:
	boost_pythoncore_d.lib
	pythoncore_d.lib

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:

extern void PythonInit();
extern void 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:

extern void PythonInitHandles();
extern void 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:

MyPyHandle* g_PyHandle = NULL;
MyPyHandle *GetPyHandle()
{
	return PyHandle ;
}

And in your constructor of your PyHandle add a call to set the instance when you make a new one:

MyPyHandle::MyPyHandle() : PyHandle()
{
	g_PyHandle = this;
	Register();
}

Note: Its important to have Register here other wise it wont work!

And finally in your game rules constructor make a new PyHandle:

CGameRules::CGameRules()
{

	//other stuff here

	// Start our Python Handle
	if (!GetPyHandle())
		new MyPyHandle();
}

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 already there
	REG( MyModule ); //this is your new module (change the name to match yours)
}

Some interfaces for the Source SDK have already 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.

Todo: more