6 * Copyright (C) 2003, 2007, 2008, 2009 Thomas Perl <thp@thpinfo.com>
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
35 static void tennixpy_get_bot_name(InputDevice
*device
, char *dest
, int maxlen
);
36 static PyObject
* tennixpy_register_bot(PyObject
* self
, PyObject
* bot_class
);
37 static PyObject
* tennixpy_get_ball_pos(PyObject
* self
, PyObject
* gamestate
);
38 static PyObject
* tennixpy_get_power(PyObject
* self
, PyObject
* args
);
39 static PyObject
* tennixpy_get_position(PyObject
* self
, PyObject
* args
);
40 static PyObject
* tennixpy_create_module(void);
42 struct InputDevicePython
{
43 PyObject
* py_bot_class
;
48 /* This saves our current Python thread state */
49 static PyThreadState
*_py_save
;
51 static PyMethodDef TennixMethods
[] = {
52 {"register_bot", tennixpy_register_bot
, METH_O
, "Register a new bot"},
53 {"get_ball_pos", tennixpy_get_ball_pos
, METH_O
, "Gets the ball position"},
54 {"get_position", tennixpy_get_position
, METH_VARARGS
, "Get position of player"},
55 {"get_power", tennixpy_get_power
, METH_VARARGS
, "Get power of player"},
56 {NULL
, NULL
, 0, NULL
} /* Sentinel */
59 PyObject
* tennixpy_create_module(void)
62 module
= Py_InitModule("tennix", TennixMethods
);
63 PyModule_AddIntConstant(module
, "INPUT_AXIS_X", INPUT_AXIS_X
);
64 PyModule_AddIntConstant(module
, "INPUT_AXIS_Y", INPUT_AXIS_Y
);
65 PyModule_AddIntConstant(module
, "INPUT_KEY_HIT", INPUT_KEY_HIT
);
66 PyModule_AddIntConstant(module
, "INPUT_KEY_TOPSPIN", INPUT_KEY_TOPSPIN
);
67 PyModule_AddIntConstant(module
, "INPUT_KEY_SMASH", INPUT_KEY_SMASH
);
72 tennixpy_create_bot(InputDevice
*device
, GameState
*s
, int player_id
)
74 InputDevicePython
*pydevice
= (InputDevicePython
*)device
->user_data
;
75 PyObject
*bot_class
= pydevice
->py_bot_class
;
81 PyEval_RestoreThread(_py_save
);
82 if (PyType_Check(bot_class
)) {
83 gamestate
= PyCObject_FromVoidPtr((void*)s
, NULL
);
84 assert(gamestate
!= NULL
);
85 args
= Py_BuildValue("(Oi)", gamestate
, player_id
);
88 o
= PyObject_CallObject(bot_class
, args
);
91 fprintf(stderr
, "cannot create instance\n");
95 fprintf(stderr
, "Typecheck failed\n");
97 _py_save
= PyEval_SaveThread();
102 void tennixpy_destroy_bot(InputDevice
*device
)
104 InputDevicePython
*pydevice
= (InputDevicePython
*)device
->user_data
;
105 PyObject
*bot
= pydevice
->py_bot
;
107 PyObject
* finish_func
;
108 PyEval_RestoreThread(_py_save
);
109 finish_func
= PyObject_GetAttrString(bot
, "finish");
110 assert(finish_func
!= NULL
);
111 Py_DECREF(PyObject_CallObject(finish_func
, NULL
));
112 Py_DECREF(finish_func
);
114 _py_save
= PyEval_SaveThread();
117 float tennixpy_bot_get_axis(InputDevice
*device
, int axis
)
119 InputDevicePython
*pydevice
= (InputDevicePython
*)device
->user_data
;
120 PyObject
*bot
= pydevice
->py_bot
;
123 PyObject
* get_axis_func
;
127 PyEval_RestoreThread(_py_save
);
129 get_axis_func
= PyObject_GetAttrString(bot
, "get_axis");
130 assert(get_axis_func
!= NULL
);
132 args
= Py_BuildValue("(i)", axis
);
133 r
= PyObject_CallObject(get_axis_func
, args
);
134 Py_DECREF(get_axis_func
);
140 if (PyFloat_Check(r
)) {
141 result
= (float)PyFloat_AsDouble(r
);
143 fprintf(stderr
, "Unexpected value from python\n");
148 _py_save
= PyEval_SaveThread();
152 char tennixpy_bot_get_key(InputDevice
*device
, int key
)
154 InputDevicePython
*pydevice
= (InputDevicePython
*)device
->user_data
;
155 PyObject
*bot
= pydevice
->py_bot
;
158 PyObject
* get_key_func
;
162 PyEval_RestoreThread(_py_save
);
164 get_key_func
= PyObject_GetAttrString(bot
, "get_key");
165 assert(get_key_func
!= NULL
);
167 args
= Py_BuildValue("(i)", key
);
168 r
= PyObject_CallObject(get_key_func
, args
);
169 Py_DECREF(get_key_func
);
177 } else if (r
== Py_False
) {
180 fprintf(stderr
, "Unexpected value from python\n");
185 _py_save
= PyEval_SaveThread();
190 input_add_python_bot(PyObject
* bot_class
)
192 InputDevice
*device
= input_add_device();
194 if (device
== NULL
) {
195 fprintf(stderr
, "Warning: Cannot add any more Python bots.\n");
196 // We carry a ref of bot_class, so give it up here
197 Py_DECREF(bot_class
);
201 device
->type
= INPUT_TYPE_AI_PYTHON
;
202 device
->icon
= GR_INPUT_AI
;
204 InputDevicePython
*pydevice
= new InputDevicePython
;
205 pydevice
->py_bot_class
= bot_class
;
206 pydevice
->py_bot
= NULL
;
207 device
->user_data
= (void*)pydevice
;
208 tennixpy_get_bot_name(device
, device
->name
, INPUT_DEVICE_NAME_MAX
);
211 PyObject
* tennixpy_register_bot(PyObject
* self
, PyObject
* bot_class
)
213 assert(self
== NULL
);
214 if (PyType_Check(bot_class
)) {
215 /* FIXME: check if all required attrs are here */
216 input_add_python_bot(bot_class
);
217 Py_INCREF(bot_class
);
219 return PyErr_Format(PyExc_TypeError
, "This function needs a bot class to work");
225 void tennixpy_get_bot_name(InputDevice
*device
, char* dest
, int maxlen
)
227 InputDevicePython
*pydevice
= (InputDevicePython
*)device
->user_data
;
228 PyObject
*bot_class
= pydevice
->py_bot_class
;
231 name
= PyObject_GetAttrString(bot_class
, "name");
233 if (PyString_Check(name
) && name
!= NULL
) {
234 strncpy(dest
, PyString_AsString(name
), maxlen
);
236 strncpy(dest
, "<unknown pybot>", maxlen
);
242 PyObject
* tennixpy_get_ball_pos(PyObject
* self
, PyObject
* gamestate
)
247 assert(self
== NULL
);
249 if (PyCObject_Check(gamestate
)) {
250 s
= (GameState
*)PyCObject_AsVoidPtr(gamestate
);
251 r
= Py_BuildValue("(dd)", (double)(s
->ball
.x
), (double)(s
->ball
.y
- s
->ball
.z
));
254 return PyErr_Format(PyExc_TypeError
, "This function needs a GameState to work on");
258 PyObject
* tennixpy_get_power(PyObject
* self
, PyObject
* args
)
266 assert(self
== NULL
);
268 assert(PyTuple_Check(args
));
270 if (PyObject_Length(args
) != 2) {
271 return PyErr_Format(PyExc_TypeError
, "This function takes exactly 2 parameters");
274 gamestate
= PyTuple_GetItem(args
, 0);
275 player_id
= PyTuple_GetItem(args
, 1);
277 if (PyInt_Check(player_id
)) {
278 player
= (int)PyInt_AsLong(player_id
);
280 return PyErr_Format(PyExc_TypeError
, "Invalid player_id in second argument");
282 if (PyCObject_Check(gamestate
)) {
283 s
= (GameState
*)PyCObject_AsVoidPtr(gamestate
);
284 return PyFloat_FromDouble((double)(PLAYER(s
, player
).power
));
286 return PyErr_Format(PyExc_TypeError
, "First argument is not a GameState");
290 PyObject
* tennixpy_get_position(PyObject
* self
, PyObject
* args
)
298 assert(self
== NULL
);
299 assert(PyTuple_Check(args
));
301 if (PyObject_Length(args
) != 2) {
302 return PyErr_Format(PyExc_TypeError
, "This function takes exactly 2 parameters");
305 gamestate
= PyTuple_GetItem(args
, 0);
306 player_id
= PyTuple_GetItem(args
, 1);
308 if (PyInt_Check(player_id
)) {
309 player
= (int)PyInt_AsLong(player_id
);
311 return PyErr_Format(PyExc_TypeError
, "Invalid player_id in second argument");
313 if (PyCObject_Check(gamestate
)) {
314 s
= (GameState
*)PyCObject_AsVoidPtr(gamestate
);
315 return Py_BuildValue("(dd)", (double)(PLAYER(s
, player
).x
), (double)(PLAYER(s
, player
).y
));
317 return PyErr_Format(PyExc_TypeError
, "First argument is not a GameState");
321 void tennixpy_init(TennixArchive
& tnxar
)
323 PyObject
* tennix_module
;
326 setenv("PYTHONPATH", ".", 1);
327 PyEval_InitThreads();
329 tennix_module
= tennixpy_create_module();
332 while (!tnxar
.endOfFile()) {
333 const char *filename
= tnxar
.getItemFilename();
334 if (strcmp(".py", filename
+ strlen(filename
) - 3) == 0) {
335 data
= tnxar
.getItemBytes();
336 if (PyRun_SimpleString(data
) != 0) {
344 Py_DECREF(tennix_module
);
345 _py_save
= PyEval_SaveThread();
348 void tennixpy_unregister_bot(InputDevice
*device
)
350 InputDevicePython
*pydevice
= (InputDevicePython
*)device
->user_data
;
351 PyEval_RestoreThread(_py_save
);
352 Py_XDECREF(pydevice
->py_bot
);
353 _py_save
= PyEval_SaveThread();
357 void tennixpy_uninit()
359 PyEval_RestoreThread(_py_save
);
361 * FIXME: We _should_ run Py_Finalize here, but it makes
362 * Tennix crash, so we just tear it down without calling it.
367 #endif /* HAVE_PYTHON */