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 PyObject
* tennixpy_register_bot(PyObject
* self
, PyObject
* bot_class
);
36 PyObject
* tennixpy_get_ball_pos(PyObject
* self
, PyObject
* gamestate
);
37 PyObject
* tennixpy_get_power(PyObject
* self
, PyObject
* args
);
38 PyObject
* tennixpy_get_position(PyObject
* self
, PyObject
* args
);
39 PyObject
* tennixpy_create_module(void);
42 struct InputDevicePython
{
43 PyObject
* py_bot_class
;
48 /* This saves our current Python thread state */
49 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
);
209 fprintf(stderr
, " %s", device
->name
);
212 PyObject
* tennixpy_register_bot(PyObject
* self
, PyObject
* bot_class
)
214 assert(self
== NULL
);
215 if (PyType_Check(bot_class
)) {
216 /* FIXME: check if all required attrs are here */
217 input_add_python_bot(bot_class
);
218 Py_INCREF(bot_class
);
220 return PyErr_Format(PyExc_TypeError
, "This function needs a bot class to work");
226 void tennixpy_get_bot_name(InputDevice
*device
, char* dest
, int maxlen
)
228 InputDevicePython
*pydevice
= (InputDevicePython
*)device
->user_data
;
229 PyObject
*bot_class
= pydevice
->py_bot_class
;
232 name
= PyObject_GetAttrString(bot_class
, "name");
234 if (PyString_Check(name
) && name
!= NULL
) {
235 strncpy(dest
, PyString_AsString(name
), maxlen
);
237 strncpy(dest
, "<unknown pybot>", maxlen
);
243 PyObject
* tennixpy_get_ball_pos(PyObject
* self
, PyObject
* gamestate
)
248 assert(self
== NULL
);
250 if (PyCObject_Check(gamestate
)) {
251 s
= (GameState
*)PyCObject_AsVoidPtr(gamestate
);
252 r
= Py_BuildValue("(dd)", (double)(s
->ball
.x
), (double)(s
->ball
.y
- s
->ball
.z
));
255 return PyErr_Format(PyExc_TypeError
, "This function needs a GameState to work on");
259 PyObject
* tennixpy_get_power(PyObject
* self
, PyObject
* args
)
267 assert(self
== NULL
);
269 assert(PyTuple_Check(args
));
271 if (PyObject_Length(args
) != 2) {
272 return PyErr_Format(PyExc_TypeError
, "This function takes exactly 2 parameters");
275 gamestate
= PyTuple_GetItem(args
, 0);
276 player_id
= PyTuple_GetItem(args
, 1);
278 if (PyInt_Check(player_id
)) {
279 player
= (int)PyInt_AsLong(player_id
);
281 return PyErr_Format(PyExc_TypeError
, "Invalid player_id in second argument");
283 if (PyCObject_Check(gamestate
)) {
284 s
= (GameState
*)PyCObject_AsVoidPtr(gamestate
);
285 return PyFloat_FromDouble((double)(PLAYER(s
, player
).power
));
287 return PyErr_Format(PyExc_TypeError
, "First argument is not a GameState");
291 PyObject
* tennixpy_get_position(PyObject
* self
, PyObject
* args
)
299 assert(self
== NULL
);
300 assert(PyTuple_Check(args
));
302 if (PyObject_Length(args
) != 2) {
303 return PyErr_Format(PyExc_TypeError
, "This function takes exactly 2 parameters");
306 gamestate
= PyTuple_GetItem(args
, 0);
307 player_id
= PyTuple_GetItem(args
, 1);
309 if (PyInt_Check(player_id
)) {
310 player
= (int)PyInt_AsLong(player_id
);
312 return PyErr_Format(PyExc_TypeError
, "Invalid player_id in second argument");
314 if (PyCObject_Check(gamestate
)) {
315 s
= (GameState
*)PyCObject_AsVoidPtr(gamestate
);
316 return Py_BuildValue("(dd)", (double)(PLAYER(s
, player
).x
), (double)(PLAYER(s
, player
).y
));
318 return PyErr_Format(PyExc_TypeError
, "First argument is not a GameState");
322 void tennixpy_init(TennixArchive
& tnxar
)
324 PyObject
* tennix_module
;
325 /*PyObject* bot_module;*/
328 /*const char* argv[] = {""};*/
330 /* Search for modules in CWD */
331 setenv("PYTHONPATH", ".", 1);
332 PyEval_InitThreads();
334 tennix_module
= tennixpy_create_module();
335 /*Py_Main(1, argv);*/
336 /*bot_module = PyImport_ImportModule("defaultbot");
337 if (bot_module == NULL) {
340 Py_DECREF(bot_module);*/
342 if (tnxar
.setItemFilename("defaultbot.py") != 0) {
343 fprintf(stderr
, "Loading computer players:");
344 data
= tnxar
.getItemBytes();
345 if (PyRun_SimpleString(data
) != 0) {
348 fprintf(stderr
, ".\n");
353 /*fp = fopen("defaultbot.py", "r");
354 PyRun_SimpleFile(fp, "defaultbot.py");
357 Py_DECREF(tennix_module
);
358 _py_save
= PyEval_SaveThread();
361 void tennixpy_unregister_bot(InputDevice
*device
)
363 InputDevicePython
*pydevice
= (InputDevicePython
*)device
->user_data
;
364 PyEval_RestoreThread(_py_save
);
365 Py_XDECREF(pydevice
->py_bot
);
366 _py_save
= PyEval_SaveThread();
370 void tennixpy_uninit()
372 PyEval_RestoreThread(_py_save
);
374 * FIXME: We _should_ run Py_Finalize here, but it makes
375 * Tennix crash, so we just tear it down without calling it.
380 #endif /* HAVE_PYTHON */