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,
33 /* This saves our current Python thread state */
34 PyThreadState
* _py_save
;
36 static PyMethodDef TennixMethods
[] = {
37 {"register_bot", tennixpy_register_bot
, METH_O
, "Register a new bot"},
38 {"get_ball_pos", tennixpy_get_ball_pos
, METH_O
, "Gets the ball position"},
39 {"get_position", tennixpy_get_position
, METH_VARARGS
, "Get position of player"},
40 {"get_power", tennixpy_get_power
, METH_VARARGS
, "Get power of player"},
41 {NULL
, NULL
, 0, NULL
} /* Sentinel */
44 PyObject
* tennixpy_create_module(void)
47 module
= Py_InitModule("tennix", TennixMethods
);
48 PyModule_AddIntConstant(module
, "INPUT_AXIS_X", INPUT_AXIS_X
);
49 PyModule_AddIntConstant(module
, "INPUT_AXIS_Y", INPUT_AXIS_Y
);
50 PyModule_AddIntConstant(module
, "INPUT_KEY_HIT", INPUT_KEY_HIT
);
51 PyModule_AddIntConstant(module
, "INPUT_KEY_TOPSPIN", INPUT_KEY_TOPSPIN
);
52 PyModule_AddIntConstant(module
, "INPUT_KEY_SMASH", INPUT_KEY_SMASH
);
56 PyObject
* tennixpy_create_bot(PyObject
* bot_class
, GameState
* s
, int player_id
)
62 PyEval_RestoreThread(_py_save
);
63 if (PyType_Check(bot_class
)) {
64 gamestate
= PyCObject_FromVoidPtr((void*)s
, NULL
);
65 assert(gamestate
!= NULL
);
66 args
= Py_BuildValue("(Oi)", gamestate
, player_id
);
69 o
= PyObject_CallObject(bot_class
, args
);
72 fprintf(stderr
, "cannot create instance\n");
76 fprintf(stderr
, "Typecheck failed\n");
78 _py_save
= PyEval_SaveThread();
83 void tennixpy_destroy_bot(PyObject
* bot
)
85 PyObject
* finish_func
;
86 PyEval_RestoreThread(_py_save
);
87 finish_func
= PyObject_GetAttrString(bot
, "finish");
88 assert(finish_func
!= NULL
);
89 Py_DECREF(PyObject_CallObject(finish_func
, NULL
));
90 Py_DECREF(finish_func
);
92 _py_save
= PyEval_SaveThread();
95 float tennixpy_bot_get_axis(PyObject
* bot
, int axis
)
98 PyObject
* get_axis_func
;
102 PyEval_RestoreThread(_py_save
);
104 get_axis_func
= PyObject_GetAttrString(bot
, "get_axis");
105 assert(get_axis_func
!= NULL
);
107 args
= Py_BuildValue("(i)", axis
);
108 r
= PyObject_CallObject(get_axis_func
, args
);
109 Py_DECREF(get_axis_func
);
115 if (PyFloat_Check(r
)) {
116 result
= (float)PyFloat_AsDouble(r
);
118 fprintf(stderr
, "Unexpected value from python\n");
123 _py_save
= PyEval_SaveThread();
127 char tennixpy_bot_get_key(PyObject
* bot
, int key
)
130 PyObject
* get_key_func
;
134 PyEval_RestoreThread(_py_save
);
136 get_key_func
= PyObject_GetAttrString(bot
, "get_key");
137 assert(get_key_func
!= NULL
);
139 args
= Py_BuildValue("(i)", key
);
140 r
= PyObject_CallObject(get_key_func
, args
);
141 Py_DECREF(get_key_func
);
149 } else if (r
== Py_False
) {
152 fprintf(stderr
, "Unexpected value from python\n");
157 _py_save
= PyEval_SaveThread();
161 PyObject
* tennixpy_register_bot(PyObject
* self
, PyObject
* bot_class
)
163 assert(self
== NULL
);
164 if (PyType_Check(bot_class
)) {
165 /* FIXME: check if all required attrs are here */
166 input_add_python_bot(bot_class
);
167 Py_INCREF(bot_class
);
169 return PyErr_Format(PyExc_TypeError
, "This function needs a bot class to work");
175 void tennixpy_get_bot_name(PyObject
* bot_class
, char* dest
, int maxlen
)
179 name
= PyObject_GetAttrString(bot_class
, "name");
181 if (PyString_Check(name
) && name
!= NULL
) {
182 strncpy(dest
, PyString_AsString(name
), maxlen
);
184 strncpy(dest
, "<unknown pybot>", maxlen
);
190 PyObject
* tennixpy_get_ball_pos(PyObject
* self
, PyObject
* gamestate
)
195 assert(self
== NULL
);
197 if (PyCObject_Check(gamestate
)) {
198 s
= (GameState
*)PyCObject_AsVoidPtr(gamestate
);
199 r
= Py_BuildValue("(dd)", (double)(s
->ball
.x
), (double)(s
->ball
.y
- s
->ball
.z
));
202 return PyErr_Format(PyExc_TypeError
, "This function needs a GameState to work on");
206 PyObject
* tennixpy_get_power(PyObject
* self
, PyObject
* args
)
214 assert(self
== NULL
);
216 assert(PyTuple_Check(args
));
218 if (PyObject_Length(args
) != 2) {
219 return PyErr_Format(PyExc_TypeError
, "This function takes exactly 2 parameters");
222 gamestate
= PyTuple_GetItem(args
, 0);
223 player_id
= PyTuple_GetItem(args
, 1);
225 if (PyInt_Check(player_id
)) {
226 player
= (int)PyInt_AsLong(player_id
);
228 return PyErr_Format(PyExc_TypeError
, "Invalid player_id in second argument");
230 if (PyCObject_Check(gamestate
)) {
231 s
= (GameState
*)PyCObject_AsVoidPtr(gamestate
);
232 return PyFloat_FromDouble((double)(PLAYER(s
, player
).power
));
234 return PyErr_Format(PyExc_TypeError
, "First argument is not a GameState");
238 PyObject
* tennixpy_get_position(PyObject
* self
, PyObject
* args
)
246 assert(self
== NULL
);
247 assert(PyTuple_Check(args
));
249 if (PyObject_Length(args
) != 2) {
250 return PyErr_Format(PyExc_TypeError
, "This function takes exactly 2 parameters");
253 gamestate
= PyTuple_GetItem(args
, 0);
254 player_id
= PyTuple_GetItem(args
, 1);
256 if (PyInt_Check(player_id
)) {
257 player
= (int)PyInt_AsLong(player_id
);
259 return PyErr_Format(PyExc_TypeError
, "Invalid player_id in second argument");
261 if (PyCObject_Check(gamestate
)) {
262 s
= (GameState
*)PyCObject_AsVoidPtr(gamestate
);
263 return Py_BuildValue("(dd)", (double)(PLAYER(s
, player
).x
), (double)(PLAYER(s
, player
).y
));
265 return PyErr_Format(PyExc_TypeError
, "First argument is not a GameState");
269 void tennixpy_init(TennixArchive
& tnxar
)
271 PyObject
* tennix_module
;
272 /*PyObject* bot_module;*/
275 /*const char* argv[] = {""};*/
277 /* Search for modules in CWD */
278 setenv("PYTHONPATH", ".", 1);
279 PyEval_InitThreads();
281 tennix_module
= tennixpy_create_module();
282 /*Py_Main(1, argv);*/
283 /*bot_module = PyImport_ImportModule("defaultbot");
284 if (bot_module == NULL) {
287 Py_DECREF(bot_module);*/
289 if (tnxar
.setItemFilename("defaultbot.py") != 0) {
290 fprintf(stderr
, "Loading computer players:");
291 data
= tnxar
.getItemBytes();
292 if (PyRun_SimpleString(data
) != 0) {
295 fprintf(stderr
, ".\n");
300 /*fp = fopen("defaultbot.py", "r");
301 PyRun_SimpleFile(fp, "defaultbot.py");
304 Py_DECREF(tennix_module
);
305 _py_save
= PyEval_SaveThread();
308 void tennixpy_unregister_bot(PyObject
* bot
)
310 PyEval_RestoreThread(_py_save
);
312 _py_save
= PyEval_SaveThread();
315 void tennixpy_uninit()
317 PyEval_RestoreThread(_py_save
);
319 * FIXME: We _should_ run Py_Finalize here, but it makes
320 * Tennix crash, so we just tear it down without calling it.