Streamline the archive loading mechanism
[tennix.git] / tennixpy.cc
blob7f2c87ea4426109f118f42b512de7d44c337249f
3 /**
5 * Tennix! SDL Port
6 * Copyright (C) 2003, 2007, 2008, 2009 Thomas Perl <thp@thpinfo.com>
7 *
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,
21 * MA 02110-1301, USA.
23 **/
25 #ifdef TENNIX_PYTHON
27 #include <Python.h>
29 #include "game.h"
30 #include "archive.hh"
31 #include "tennixpy.h"
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)
46 PyObject* module;
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);
53 return module;
56 PyObject* tennixpy_create_bot(PyObject* bot_class, GameState* s, int player_id)
58 PyObject* o = NULL;
59 PyObject* args;
60 PyObject* gamestate;
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);
67 assert(args != NULL);
68 Py_DECREF(gamestate);
69 o = PyObject_CallObject(bot_class, args);
70 Py_DECREF(args);
71 if (o == NULL) {
72 fprintf(stderr, "cannot create instance\n");
73 PyErr_Print();
75 } else {
76 fprintf(stderr, "Typecheck failed\n");
78 _py_save = PyEval_SaveThread();
80 return o;
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);
91 Py_DECREF(bot);
92 _py_save = PyEval_SaveThread();
95 float tennixpy_bot_get_axis(PyObject* bot, int axis)
97 PyObject* args;
98 PyObject* get_axis_func;
99 PyObject* r;
100 float result = 0.0;
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);
110 Py_DECREF(args);
112 if (r == NULL) {
113 PyErr_Print();
114 } else {
115 if (PyFloat_Check(r)) {
116 result = (float)PyFloat_AsDouble(r);
117 } else {
118 fprintf(stderr, "Unexpected value from python\n");
120 Py_DECREF(r);
123 _py_save = PyEval_SaveThread();
124 return result;
127 char tennixpy_bot_get_key(PyObject* bot, int key)
129 PyObject* args;
130 PyObject* get_key_func;
131 PyObject* r;
132 char result = 0;
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);
142 Py_DECREF(args);
144 if (r == NULL) {
145 PyErr_Print();
146 } else {
147 if (r == Py_True) {
148 result = 1;
149 } else if (r == Py_False) {
150 result = 0;
151 } else {
152 fprintf(stderr, "Unexpected value from python\n");
154 Py_DECREF(r);
157 _py_save = PyEval_SaveThread();
158 return result;
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);
168 } else {
169 return PyErr_Format(PyExc_TypeError, "This function needs a bot class to work");
172 Py_RETURN_NONE;
175 void tennixpy_get_bot_name(PyObject* bot_class, char* dest, int maxlen)
177 PyObject *name;
179 name = PyObject_GetAttrString(bot_class, "name");
181 if (PyString_Check(name) && name != NULL) {
182 strncpy(dest, PyString_AsString(name), maxlen);
183 } else {
184 strncpy(dest, "<unknown pybot>", maxlen);
187 Py_XDECREF(name);
190 PyObject* tennixpy_get_ball_pos(PyObject* self, PyObject* gamestate)
192 PyObject* r;
193 GameState* s;
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));
200 return r;
201 } else {
202 return PyErr_Format(PyExc_TypeError, "This function needs a GameState to work on");
206 PyObject* tennixpy_get_power(PyObject* self, PyObject* args)
208 PyObject* gamestate;
209 PyObject* player_id;
211 GameState* s;
212 int player;
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);
227 } else {
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));
233 } else {
234 return PyErr_Format(PyExc_TypeError, "First argument is not a GameState");
238 PyObject* tennixpy_get_position(PyObject* self, PyObject* args)
240 PyObject* gamestate;
241 PyObject* player_id;
243 GameState* s;
244 int player;
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);
258 } else {
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));
264 } else {
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;*/
273 /*FILE* fp;*/
274 char* data;
275 /*const char* argv[] = {""};*/
277 /* Search for modules in CWD */
278 setenv("PYTHONPATH", ".", 1);
279 PyEval_InitThreads();
280 Py_Initialize();
281 tennix_module = tennixpy_create_module();
282 /*Py_Main(1, argv);*/
283 /*bot_module = PyImport_ImportModule("defaultbot");
284 if (bot_module == NULL) {
285 PyErr_Print();
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) {
293 PyErr_Print();
294 } else {
295 fprintf(stderr, ".\n");
297 free(data);
300 /*fp = fopen("defaultbot.py", "r");
301 PyRun_SimpleFile(fp, "defaultbot.py");
302 fclose(fp);*/
304 Py_DECREF(tennix_module);
305 _py_save = PyEval_SaveThread();
308 void tennixpy_unregister_bot(PyObject* bot)
310 PyEval_RestoreThread(_py_save);
311 Py_DECREF(bot);
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.
322 /*Py_Finalize();*/
325 #endif