4 // Copyright (C) 2006 Matthias Braun <matze@braunis.de>
6 // This program is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU General Public License
8 // as published by the Free Software Foundation; either version 2
9 // of the License, or (at your option) any later version.
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
16 // You should have received a copy of the GNU General Public License
17 // along with this program; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
22 #include "script_manager.hpp"
29 #include <sqstdblob.h>
30 #include <sqstdmath.h>
31 #include <sqstdstring.h>
34 #include "console.hpp"
36 #include "scripting/wrapper.hpp"
37 #include "scripting/wrapper_util.hpp"
38 #include "scripting/squirrel_error.hpp"
39 #include "physfs/physfs_stream.hpp"
41 using namespace Scripting;
43 ScriptManager* ScriptManager::instance = NULL;
45 static void printfunc(HSQUIRRELVM, const char* str, ...)
49 va_start(arglist, str);
50 vsprintf(buf, str, arglist);
51 Console::output << (const char*) buf << std::flush;
55 ScriptManager::ScriptManager()
60 throw std::runtime_error("Couldn't initialize squirrel vm");
61 sq_setforeignptr(vm, (SQUserPointer) this);
63 // register squirrel libs
65 if(sqstd_register_bloblib(vm) < 0)
66 throw SquirrelError(vm, "Couldn't register blob lib");
67 if(sqstd_register_mathlib(vm) < 0)
68 throw SquirrelError(vm, "Couldn't register math lib");
69 if(sqstd_register_stringlib(vm) < 0)
70 throw SquirrelError(vm, "Couldn't register string lib");
71 // register supertux API
72 register_supertux_wrapper(vm);
75 // register print function
76 sq_setprintfunc(vm, printfunc);
77 // register default error handlers
78 sqstd_seterrorhandlers(vm);
80 // try to load default script
82 std::string filename = "scripts/default.nut";
83 IFileStream stream(filename);
84 Scripting::compile_and_run(vm, stream, filename);
85 } catch(std::exception& e) {
86 log_warning << "Couldn't load default.nut: " << e.what() << std::endl;
90 ScriptManager::ScriptManager(ScriptManager* parent)
92 this->parent = parent;
94 parent->childs.push_back(this);
97 ScriptManager::~ScriptManager()
99 for(SquirrelVMs::iterator i = squirrel_vms.begin();
100 i != squirrel_vms.end(); ++i)
101 sq_release(vm, &(i->vm_obj));
104 parent->childs.erase(
105 std::remove(parent->childs.begin(), parent->childs.end(), this),
106 parent->childs.end());
113 ScriptManager::create_thread(bool leave_thread_on_stack)
115 HSQUIRRELVM new_vm = sq_newthread(vm, 64);
117 throw SquirrelError(vm, "Couldn't create new VM");
118 sq_setforeignptr(new_vm, (SQUserPointer) this);
120 // retrieve reference to thread from stack and increase refcounter
122 sq_resetobject(&vm_obj);
123 if(SQ_FAILED(sq_getstackobj(vm, -1, &vm_obj))) {
124 throw SquirrelError(vm, "Couldn't get coroutine vm from stack");
126 sq_addref(vm, &vm_obj);
128 if(!leave_thread_on_stack)
131 squirrel_vms.push_back(SquirrelVM(new_vm, vm_obj));
137 ScriptManager::update()
139 for(SquirrelVMs::iterator i = squirrel_vms.begin(); i != squirrel_vms.end(); ) {
140 SquirrelVM& squirrel_vm = *i;
141 int vm_state = sq_getvmstate(squirrel_vm.vm);
143 if(vm_state == SQ_VMSTATE_SUSPENDED && squirrel_vm.wakeup_time > 0 && game_time >= squirrel_vm.wakeup_time) {
144 squirrel_vm.waiting_for_events = WakeupData(NO_EVENT);
146 if(SQ_FAILED(sq_wakeupvm(squirrel_vm.vm, false, false))) {
147 throw SquirrelError(squirrel_vm.vm, "Couldn't resume script");
149 } catch(std::exception& e) {
150 std::cerr << "Problem executing script: " << e.what() << "\n";
151 sq_release(vm, &squirrel_vm.vm_obj);
152 i = squirrel_vms.erase(i);
157 if (vm_state != SQ_VMSTATE_SUSPENDED) {
158 sq_release(vm, &(squirrel_vm.vm_obj));
159 i = squirrel_vms.erase(i);
167 ScriptManager::set_wakeup_event(HSQUIRRELVM vm, WakeupData event, float timeout)
169 assert(event.type >= 0 && event.type < WAKEUP_EVENT_COUNT);
170 // find the VM in the list and update it
171 for(SquirrelVMs::iterator i = squirrel_vms.begin();
172 i != squirrel_vms.end(); ++i) {
173 SquirrelVM& squirrel_vm = *i;
174 if(squirrel_vm.vm == vm)
176 squirrel_vm.waiting_for_events = event;
179 squirrel_vm.wakeup_time = -1;
181 squirrel_vm.wakeup_time = game_time + timeout;
189 ScriptManager::fire_wakeup_event(WakeupData event)
191 assert(event.type >= 0 && event.type < WAKEUP_EVENT_COUNT);
192 for(SquirrelVMs::iterator i = squirrel_vms.begin();
193 i != squirrel_vms.end(); ++i) {
195 if(vm.waiting_for_events.type == event.type
196 && vm.waiting_for_events.type != NO_EVENT) {
197 vm.wakeup_time = game_time;
202 for(std::vector<ScriptManager*>::iterator i = childs.begin();
203 i != childs.end(); ++i) {
204 ScriptManager* child = *i;
205 child->fire_wakeup_event(event);
210 ScriptManager::set_wakeup_event(HSQUIRRELVM vm, WakeupEvent event, float timeout)
212 set_wakeup_event(vm, WakeupData(event), timeout);
216 ScriptManager::fire_wakeup_event(WakeupEvent event)
218 fire_wakeup_event(WakeupData(event));
221 ScriptManager::SquirrelVM::SquirrelVM(HSQUIRRELVM arg_vm, HSQOBJECT arg_obj)
222 : vm(arg_vm), vm_obj(arg_obj)
224 waiting_for_events = WakeupData(NO_EVENT);