f2e53b28725457d6d458fe60e9df600a56e2a70a
[supertux.git] / src / scripting / script_interpreter.cpp
1 #include <config.h>
2
3 #include "script_interpreter.h"
4
5 #include <stdarg.h>
6 #include <stdexcept>
7 #include <sstream>
8 #include <sqstdio.h>
9 #include <sqstdaux.h>
10 #include <sqstdblob.h>
11 #include <sqstdsystem.h>
12 #include <sqstdmath.h>
13 #include <sqstdstring.h>
14
15 #include "wrapper.h"
16 #include "wrapper_util.h"
17
18 static void printfunc(HSQUIRRELVM, const char* str, ...)
19 {
20   va_list arglist;
21   va_start(arglist, str);
22   vprintf(str, arglist);
23   va_end(arglist);
24 }
25
26 ScriptInterpreter* ScriptInterpreter::_current = 0;
27
28 ScriptInterpreter::ScriptInterpreter()
29 {
30   v = sq_open(1024);
31   if(v == 0)
32     throw std::runtime_error("Couldn't initialize squirrel vm");
33
34   // register default error handlers
35   sqstd_seterrorhandlers(v);
36   // register squirrel libs
37   sq_pushroottable(v);
38   if(sqstd_register_bloblib(v) < 0)
39     throw SquirrelError(v, "Couldn't register blob lib");
40   if(sqstd_register_iolib(v) < 0)
41     throw SquirrelError(v, "Couldn't register io lib");
42   if(sqstd_register_systemlib(v) < 0)
43     throw SquirrelError(v, "Couldn't register system lib");
44   if(sqstd_register_mathlib(v) < 0)
45     throw SquirrelError(v, "Couldn't register math lib");
46   if(sqstd_register_stringlib(v) < 0)
47     throw SquirrelError(v, "Couldn't register string lib");
48
49   // register print function
50   sq_setprintfunc(v, printfunc);
51   
52   // register supertux API
53   register_functions(v, supertux_global_functions);
54   register_classes(v, supertux_classes);  
55 }
56
57 ScriptInterpreter::~ScriptInterpreter()
58 {
59 }
60
61 static SQInteger squirrel_read_char(SQUserPointer file)
62 {
63   std::istream* in = reinterpret_cast<std::istream*> (file);
64   char c = in->get();
65   if(in->eof())
66     return 0;    
67   return c;
68 }
69
70
71 void
72 ScriptInterpreter::load_script(std::istream& in, const std::string& sourcename)
73 {
74   if(sq_compile(v, squirrel_read_char, &in, sourcename.c_str(), true) < 0)
75     throw SquirrelError(v, "Couldn't parse script");
76 }
77
78 void
79 ScriptInterpreter::run_script()
80 {
81   _current = this;
82   sq_push(v, -2);
83   if(sq_call(v, 1, false) < 0)
84     throw SquirrelError(v, "Couldn't start script");
85   _current = 0;
86 }
87
88 void
89 ScriptInterpreter::expose_object(void* object, const std::string& name,
90                                  const std::string& type)
91 {
92   // part1 of registration of the instance in the root table
93   sq_pushroottable(v);
94   sq_pushstring(v, name.c_str(), -1);
95
96   // resolve class name
97   sq_pushroottable(v);
98   sq_pushstring(v, type.c_str(), -1);
99   if(sq_get(v, -2) < 0) {
100     std::ostringstream msg;
101     msg << "Couldn't resolve squirrel type '" << type << "'.";
102     throw std::runtime_error(msg.str());
103   }
104   sq_remove(v, -2); // remove roottable
105   
106   // create an instance and set pointer to c++ object
107   if(sq_createinstance(v, -1) < 0 || sq_setinstanceup(v, -1, object)) {
108     std::ostringstream msg;
109     msg << "Couldn't setup squirrel instance for object '"
110         << name << "' of type '" << type << "'.";
111     throw SquirrelError(v, msg.str());
112   }
113   
114   sq_remove(v, -2); // remove class from stack
115   
116   // part2 of registration of the instance in the root table
117   if(sq_createslot(v, -3) < 0)
118     throw SquirrelError(v, "Couldn't register object in squirrel root table");    sq_pop(v, 1);
119 }
120
121 void
122 ScriptInterpreter::suspend(float seconds)
123 {
124   resume_timer.start(seconds);
125   //sq_suspendvm(v);
126 }
127
128 void
129 ScriptInterpreter::update()
130 {
131   if(resume_timer.check()) {
132     _current = this;
133     if(sq_wakeupvm(v, false, false) < 0)
134       throw SquirrelError(v, "Couldn't resume script");
135     _current = 0;
136   }
137 }