Vegastrike 0.5.1 rc1  1.0
Original sources for Vegastrike Evolved
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
init.cpp
Go to the documentation of this file.
1 #ifdef HAVE_PYTHON
2 #include <Python.h>
3 #include <pyerrors.h>
4 #include <pythonrun.h>
5 #include <compile.h>
6 #include <eval.h>
7 #include <stdio.h>
8 #include <math.h>
9 #include <boost/version.hpp>
10 #if BOOST_VERSION != 102800
11 #if defined (_MSC_VER) && _MSC_VER <= 1200
12 #define Vector Vactor
13 #endif
14 #include <boost/python.hpp>
15 #include <boost/python/converter/from_python.hpp>
16 #if defined (_MSC_VER) && _MSC_VER <= 1200
17 #undef Vector
18 #endif
19 #else
20 #include <boost/python/class_builder.hpp>
21 #include <boost/python/detail/extension_class.hpp>
22 #endif
23 #include "configxml.h"
24 #include "vs_globals.h"
25 #include "vsfilesystem.h"
26 #include "init.h"
27 #include "python_compile.h"
28 #include "python_class.h"
29 #include "cmd/unit_generic.h"
30 #if defined (_WIN32) && !defined (__CYGWIN__)
31 #include <direct.h>
32 #endif
33 class Unit;
34 //FROM_PYTHON_SMART_POINTER(Unit)
35 #ifdef OLD_PYTHON_TEST
36 class hello
37 {
38  std::string country;
39 public: hello( const std::string &country )
40  {
41  this->country = country;
42  }
43  virtual std::string greet() const
44  {
45  return "Hello from "+country;
46  }
47  virtual ~hello()
48  {
49  VSFileSystem::vs_fprintf( stderr, "NO HELLO %d", this );
50  } //Good practice
51 };
52 
53 struct hello_callback : hello
54 {
55  //hello constructor storing initial self_ parameter
56  hello_callback( PyObject *self_, const std::string &x ) //2
57  : hello( x )
58  , self( self_ ) {}
59 
60  //In case hello is returned by-value from a wrapped function
61  hello_callback( PyObject *self_, const hello &x ) //3
62  : hello( x )
63  , self( self_ ) {}
64 
65  //Override greet to call back into Python
66  std::string greet() const //4
67  {
68  return boost::python::callback< std::string >::call_method( self, "greet" );
69  }
70  virtual ~hello_callback()
71  {
72  VSFileSystem::vs_fprintf( stderr, "NO CALLBAC %d", this );
73  }
74  //Supplies the default implementation of greet
75  static std::string default_greet( const hello &self_ ) //const // 5
76  {
77  return self_.hello::greet();
78  }
79 private:
80  PyObject *self; //1
81 };
82 
83 class MyBaseClass
84 {
85 private:
86 protected:
87  int val;
88 public: MyBaseClass( int set )
89  {
90  val = set;
91  }
92  virtual void foo( int set )
93  {
94  val = 0;
95  }
96  virtual int get()
97  {
98  return -4364;
99  }
100  virtual ~MyBaseClass() {}
101 };
102 
103 class MyDerivedClass : MyBaseClass
104 {
105 private:
106 public: MyDerivedClass( int set ) : MyBaseClass( set )
107  {
108  val = 4364;
109  }
110  virtual void foo( int set )
111  {
112  val = set;
113  }
114  virtual int get()
115  {
116  return val;
117  }
118  virtual ~MyDerivedClass() {}
119 };
120 
121 /* Simple Python configuration modifier. It modifies the attributes
122  * in the config_xml DOM; currently only works for variables in section
123  * 'data', and doesn't create new variables if necessary */
124 
125 class PythonVarConfig
126 {
127 public:
128  struct myattr
129  {
130  std::string name;
131  std::string value;
132  myattr( std::string nam, std::string val )
133  {
134  name = nam;
135  value = val;
136  }
137  };
138  std::vector< myattr >myvar;
139  std::string MyGetVariable( std::string name, int &loc ) const
140  {
141  std::vector< myattr >::const_iterator iter = myvar.begin();
142  std::string value = "";
143  if (iter)
144  while ( iter != myvar.end() ) {
145  if ( (*iter).name == name ) {
146  value = (*iter).value;
147  break;
148  }
149  ++iter;
150  }
151  return value;
152  }
153  void setVariable( const std::string &name, const std::string &value )
154  {
155  printf( "variable %s set to %s.\n", name.c_str(), value.c_str() );
156  int loc;
157  std::string newval = MyGetVariable( name, loc );
158  if ( newval.empty() )
159  myvar.push_back( myattr( name, value ) );
160  else
161  myvar[loc].value = value;
162  }
163  std::string getVariable( const std::string &name ) const
164  {
165  int loc;
166  std::string value = MyGetVariable( name, loc );
167  if ( value.empty() )
168  value = "<UNDEFINED>";
169  printf( "variable %s is %s\n", name.c_str(), value.c_str() );
170  return value;
171  }
172 };
173 
174 class PythonIOString
175 {
176 public:
177  static std::strstream buffer;
178  static void write( PythonIOString &self, string data )
179  {
180  buffer<<data;
181  }
182 };
183 std::strstream PythonIOString::buffer;
184 
185 /* Basic mode of operation:
186  * Define a module_builder per module and class_builders for each
187  * class to be exported to python
188  *
189  * <module_builder|class_builder>.def defines a function in the module or class
190  * <module_builder|class_builder>.add adds a variable to the module or class
191  *
192  * From the boost documentation (I haven't used this yet)
193  *
194  * Direct Access to Data Members
195  * Boost.Python uses the special __xxxattr__<name>__ functionality described above to allow direct access to data members through the following special functions on class_builder<> and extension_class<>:
196  *
197  * def_getter(pointer-to-member, name) // read access to the member via attribute name
198  * def_setter(pointer-to-member, name) // write access to the member via attribute name
199  * def_readonly(pointer-to-member, name) // read-only access to the member via attribute name
200  * def_read_write(pointer-to-member, name) // read/write access to the member via attribute name
201  *
202  * ( Pointer to member is &Class::member )
203  *
204  */
205 
206 #include "cmd/ai/fire.h"
207 class MyFA : public CommunicatingAI
208 {
209 public: MyFA() : CommunicatingAI( 0, 0 ) {}
210  virtual void Execute()
211  {
212  printf( "CommAI\n" );
213  }
214  virtual ~MyFA() {}
215 };
216 
217 BOOST_PYTHON_MODULE_INIT( Vegastrike )
218 {
219  /* Create a new module VS in python */
220  boost::python::module_builder vs( "VS" );
221 
222 /* boost::python::class_builder<hello,hello_callback> BaseClass(vs, "hello");
223  * BaseClass.def(boost::python::constructor<std::string>());
224  * BaseClass.def(hello::greet,"greet",hello_callback::default_greet);
225  */
226 /* boost::python::class_builder<PythonVarConfig>
227  * Var(vs, "Var");
228  * //Define a constructor. To define a constructor with multiple arguments,
229  * //do <classbuilder_type>.def(boost::python::constructor<type1,type2,...>()
230  * Var.def(boost::python::constructor<>());
231  *
232  * // Override __getattr__ and __setattr__ so that assignments to unbound variables in
233  * //a Var will be redirected to the config assignment functions
234  * Var.def(PythonVarConfig::getVariable,"__getattr__");
235  * Var.def(PythonVarConfig::setVariable,"__setattr__");
236  *
237  */
238  boost::python::class_builder< MyFA >FA( vs, "CommAI" );
239  FA.def( &MyFA::Execute, "Execute" );
240  FA.def( boost::python::constructor< > () );
241  boost::python::class_builder< PythonIOString >
242  IO( vs, "IO" );
243  IO.def( boost::python::constructor< > () );
244  /* Implement a function that implements the same interface as the write file
245  * I/O function in python. This is used to redirect output. A similar technique
246  * can be used to redirect input */
247  IO.def( PythonIOString::write, "write" );
248 }
249 //boost::python::detail::extension_instance::wrapped_objects
250 
251 /*Orders::FireAt & from_python(PyObject *p,boost::python::type<Orders::FireAt &>) {
252  * return from_python(p,boost::python::type<Orders::FireAt &>());
253  * }*/
254 #endif
255 #include "vsfilesystem.h"
256 
257 #ifdef _WIN32
258 //Python 2.5 doesn't seem to like forward-slashes.
259 #define PATHSEP "\\"
260 #else
261 #define PATHSEP "/"
262 #endif
263 
264 void Python::initpaths()
265 {
266  /*
267  * char pwd[2048];
268  * getcwd (pwd,2047);
269  * pwd[2047]='\0';
270  * for (int i=0;pwd[i]!='\0';i++) {
271  * if (pwd[i]=='\\')
272  * pwd[i]=DELIM;
273  * }
274  */
275  std::string moduledir( vs_config->getVariable( "data", "python_modules", "modules" ) );
276  std::string basesdir( vs_config->getVariable( "data", "python_bases", "bases" ) );
277 
278  /*
279  * std::string changepath ("import sys\nprint sys.path\nsys.path = ["
280  * "\""+std::string(pwd)+DELIMSTR"modules"DELIMSTR"builtin\""
281  * ",\""+std::string(pwd)+DELIMSTR+moduledir+string("\"")+
282  * ",\""+std::string(pwd)+DELIMSTR+basesdir + string("\"")+
283  * "]\n");
284  */
285  std::string modpaths( "" );
286  //Find all the mods dir (ignore homedir)
287  for (unsigned int i = 1; i < VSFileSystem::Rootdir.size(); i++) {
288  modpaths += "r\""+VSFileSystem::Rootdir[i]+PATHSEP+moduledir+PATHSEP "builtin\",";
289  modpaths += "r\""+VSFileSystem::Rootdir[i]+PATHSEP+moduledir+PATHSEP "quests\",";
290  modpaths += "r\""+VSFileSystem::Rootdir[i]+PATHSEP+moduledir+PATHSEP "missions\",";
291  modpaths += "r\""+VSFileSystem::Rootdir[i]+PATHSEP+moduledir+PATHSEP "ai\",";
292  modpaths += "r\""+VSFileSystem::Rootdir[i]+PATHSEP+moduledir+"\",";
293  modpaths += "r\""+VSFileSystem::Rootdir[i]+PATHSEP+basesdir+"\"";
294  if ( i+1 < VSFileSystem::Rootdir.size() )
295  modpaths += ",";
296  }
297  /*
298  * string::size_type backslash;
299  * while ((backslash=modpaths.find("\\"))!=std::string::npos) {
300  * modpaths[backslash]='/';
301  * }*/
302  std::string changepath( "import sys\nprint sys.path\nsys.path = ["+modpaths+"] + sys.path\n" );
303  /*
304  * std::string changepath ("import sys\nprint sys.path\nsys.path = ["
305  * "\""+VSFileSystem::datadir+DELIMSTR"modules"DELIMSTR"builtin\""
306  * ",\""+VSFileSystem::datadir+DELIMSTR+moduledir+string("\"")+
307  * ",\""+VSFileSystem::datadir+DELIMSTR+basesdir + string("\"")+
308  * "]\n");
309  */
310  VSFileSystem::vs_fprintf( stderr, "running %s", changepath.c_str() );
311  char *temppython = strdup( changepath.c_str() );
312  PyRun_SimpleString( temppython );
313  Python::reseterrors();
314  free( temppython );
315 }
316 
317 void Python::reseterrors()
318 {
319  if ( PyErr_Occurred() ) {
320  PyErr_Print();
321  PyErr_Clear();
322  fflush( stderr );
323  fflush( stdout );
324  }
325 #ifdef _DEBUG
326  fflush( stderr );
327 #endif
328 }
329 /*
330  * //PYTHON_INIT_GLOBALS(VS,UnitContainer);
331  * PYTHON_INIT_GLOBALS(VS,Unit);
332  * PYTHON_BEGIN_MODULE(VS)
333  * PYTHON_BASE_BEGIN_CLASS(VS,UnitContainer,"StoredUnit")
334  * Class.def(boost::python::constructor<Unit*>());
335  * Class.def(&UnitContainer::SetUnit,"Set");
336  * Class.def(&UnitContainer::GetUnit,"Get");
337  * PYTHON_END_CLASS(VS,UnitContainer)
338  * PYTHON_BASE_BEGIN_CLASS(VS,Unit,"Unit")
339  * Class.def(boost::python::constructor<int>());
340  * //Class.def(&UnitContainer::SetUnit,"Set");
341  * //Class.def(&UnitContainer::GetUnit,"Get");
342  * PYTHON_END_CLASS(VS,Unit)
343  * PYTHON_END_MODULE(VS)
344  * TO_PYTHON_SMART_POINTER(Unit)
345  */
346 #if BOOST_VERSION != 102800
347 static void * Vector_convertible( PyObject *p )
348 {
349  return PyTuple_Check( p ) ? p : 0;
350 }
351 
352 
353 static void Vector_construct( PyObject *source, boost::python::converter::rvalue_from_python_stage1_data *data )
354 {
355  void*const storage = ( (boost::python::converter::rvalue_from_python_storage< Vector >*)data )->storage.bytes;
356  new (storage) Vector( 0, 0, 0 );
357  //Fill in QVector values from source tuple here
358  //details left to reader.
359  Vector *vec = (Vector*) storage;
360  static char fff[4] = "fff"; //added by chuck_starchaser, to kill a warning
361  PyArg_ParseTuple( source, fff, &vec->i, &vec->j, &vec->k );
362  data->convertible = storage;
363 }
364 
365 static void QVector_construct( PyObject *source, boost::python::converter::rvalue_from_python_stage1_data *data )
366 {
367  void*const storage = ( (boost::python::converter::rvalue_from_python_storage< QVector >*)data )->storage.bytes;
368  new (storage) QVector( 0, 0, 0 );
369  //Fill in QVector values from source tuple here
370  //details left to reader.
371  QVector *vec = (QVector*) storage;
372  static char ddd[4] = "ddd"; //added by chuck_starchaser, to kill a warning
373  PyArg_ParseTuple( source, ddd, &vec->i, &vec->j, &vec->k );
374  data->convertible = storage;
375 }
376 #endif
377 
378 void Python::init()
379 {
380  static bool isinit = false;
381  if (isinit)
382  return;
383  isinit = true;
384 //initialize python library
385  Py_NoSiteFlag = 1;
386  Py_Initialize();
387  initpaths();
388 #if BOOST_VERSION != 102800
389  boost::python::converter::registry::insert( Vector_convertible, QVector_construct, boost::python::type_id< QVector > () );
390  boost::python::converter::registry::insert( Vector_convertible, Vector_construct, boost::python::type_id< Vector > () );
391 #endif
392  InitBriefing();
393  InitVS();
394  VSFileSystem::vs_fprintf( stderr, "testing VS random" );
395  std::string changepath( "import sys\nprint sys.path\n" );
396  VSFileSystem::vs_fprintf( stderr, "running %s", changepath.c_str() );
397  char *temppython = strdup( changepath.c_str() );
398  PyRun_SimpleString( temppython );
399  Python::reseterrors();
400  free( temppython );
401  InitDirector();
402  InitBase();
403 //InitVegastrike();
404 }
405 
406 void Python::test()
407 {
408  /* initialize vegastrike module so that
409  * 'import VS' works in python */
410 
411  /* There should be a python script automatically executed right after
412  * initVegastrike to rebind some of the objects into a better hierarchy,
413  * and to install wrappers for class methods, etc.
414  *
415  * This script should look something like <<EOF
416  * import VS
417  * import sys
418  *
419  * #Set up output redirection
420  * sys.stdout = VS.IO()
421  * sys.stderr = sys.stdout
422  *
423  * #Make Var look like a nested 'class'
424  * VS.Config.Var = VS.Var()
425  *
426  * EOF
427  * This should be executed with PyRun_SimpleString(char *command)
428  * See defs.py for some recipes that should go in there
429  *
430  * Other useful Python functions:
431  *
432  * PyObject* Py_CompileString(char *str, char *filename, int start)
433  * Return value: New reference.
434  * Parse and compile the Python source code in str, returning the resulting code object. The start token is given by start; this can be used to constrain the code which can be compiled and should be Py_eval_input, Py_file_input, or Py_single_input. The filename specified by filename is used to construct the code object and may appear in tracebacks or SyntaxError exception messages. This returns NULL if the code cannot be parsed or compiled.
435  *
436  * This would be the preferred mode of operation for AI scripts
437  */
438 
439 #if 0 //defined(WIN32)
440  FILE *fp = VSFileSystem::OpenFile( "config.py", "r" );
441 
442  freopen( "stderr", "w", stderr );
443  freopen( "stdout", "w", stdout );
444  changehome( true );
445  FILE *fp1 = VSFileSystem::OpenFile( "config.py", "r" );
446  returnfromhome();
447  if (fp1 == NULL)
448  fp1 = fp;
449  if (fp1 != NULL) {
450  PyRun_SimpleFile( fp, "config.py" );
451  VSFileSystem::Close( fp1 );
452  }
453 #endif
454 #ifdef OLD_PYTHON_TEST
455  //CompileRunPython ("simple_test.py");
456  //PyObject * arglist = CreateTuple (vector <PythonBasicType> ());
457  //PyObject * res = PyEval_CallObject(po, arglist);
458  //Py_DECREF(arglist);
459  //Py_XDECREF(res);
460 
461  PyRun_SimpleString(
462  "import VS\n"
463  "import sys\n"
464  "sys.stderr.write('asdf')\n"
465 //"VSConfig=VS.Var()\n"
466 //"VSConfig.test='hi'\n"
467 //"print VSConfig.test\n"
468 //"print VSConfig.undefinedvar\n"
469 //"VSConfig.__setattr__('undefined','An undefined variable')\n"
470 //"print VSConfig.__getattr__('undefined')\n"
471  "class MyAI(VS.CommAI):\n"
472  " def Execute(self):\n"
473  " sys.stdout.write('MyAI\\n')\n"
474  "hi2 = MyAI()\n"
475  "hi1 = VS.CommAI()\n"
476  "print hi1.Execute()\n"
477  "print hi2.Execute()\n"
478  );
479 #endif
480 //char buffer[128];
481 //PythonIOString::buffer << endl << '\0';
482 //vs_config->setVariable("data","test","NULL");
483 //VSFileSystem::vs_fprintf(stdout, "%s", vs_config->getVariable("data","test", string()).c_str());
484 //VSFileSystem::vs_fprintf(stdout, "output %s\n", PythonIOString::buffer.str());
485  fflush( stderr );
486  fflush( stdout );
487 }
488 
489 #endif
490