1 // -*- Mode: C++; tab-width:2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 // vi:tw=80:et:ts=2:sts=2
3 //
4 // -----------------------------------------------------------------------
5 //
6 // This file is part of RLVM, a RealLive virtual machine clone.
7 //
8 // -----------------------------------------------------------------------
9 //
10 // Copyright (C) 2008 Elliot Glaysher
11 //
12 // This program is free software; you can redistribute it and/or modify
13 // it under the terms of the GNU General Public License as published by
14 // the Free Software Foundation; either version 3 of the License, or
15 // (at your option) any later version.
16 //
17 // This program is distributed in the hope that it will be useful,
18 // but WITHOUT ANY WARRANTY; without even the implied warranty of
19 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 // GNU General Public License for more details.
21 //
22 // You should have received a copy of the GNU General Public License
23 // along with this program; if not, write to the Free Software
24 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
25 // -----------------------------------------------------------------------
26
27 #include "script_machine/script_world.h"
28
29 #include <iostream>
30 #include <typeinfo>
31 #include <sstream>
32 #include <string>
33 #include <boost/filesystem/operations.hpp>
34 #include <boost/filesystem/path.hpp>
35
36 #include "modules/module_sel.h"
37 #include "script_machine/luabind_event_system.h"
38 #include "script_machine/luabind_graphics_object.h"
39 #include "script_machine/luabind_graphics_system.h"
40 #include "script_machine/luabind_machine.h"
41 #include "script_machine/luabind_system.h"
42 #include "script_machine/luabind_utility.h"
43 #include "script_machine/script_machine.h"
44 #include "systems/base/system.h"
45
46 extern "C" {
47 #include "lua.h"
48 #include "lualib.h"
49 #include "lauxlib.h"
50 }
51
52 #include <luabind/luabind.hpp>
53
54 using namespace std;
55 using namespace luabind;
56 namespace fs = boost::filesystem;
57
ScriptWorld()58 ScriptWorld::ScriptWorld() {
59 L = lua_open();
60 luaopen_base(L);
61 luaopen_string(L);
62 luaopen_table(L);
63 InitializeLuabind(L);
64
65 luabind::globals(L)["World"] = this;
66 }
67
~ScriptWorld()68 ScriptWorld::~ScriptWorld() { lua_close(L); }
69
LoadToplevelFile(const std::string & lua_file)70 void ScriptWorld::LoadToplevelFile(const std::string& lua_file) {
71 script_dir_ = fs::path(lua_file).branch_path();
72
73 if (luaL_dofile(L, lua_file.c_str())) {
74 ostringstream oss;
75 oss << "Error while running script: " << lua_file << " ("
76 << lua_tostring(L, -1) << ")";
77 throw std::runtime_error(oss.str());
78 }
79 }
80
Import(const std::string & file_name)81 void ScriptWorld::Import(const std::string& file_name) {
82 fs::path script_path(script_dir_ / file_name);
83
84 if (!fs::exists(script_path)) {
85 ostringstream oss;
86 oss << "Could not read script file: " << script_path;
87 throw std::runtime_error(oss.str());
88 }
89
90 if (luaL_dofile(L, script_path.string().c_str())) {
91 ostringstream oss;
92 oss << "Error while running script: " << script_path << " ("
93 << lua_tostring(L, -1) << ")";
94 throw std::runtime_error(oss.str());
95 }
96 }
97
Regname() const98 std::string ScriptWorld::Regname() const {
99 ScriptMachine* machine =
100 luabind::object_cast<ScriptMachine*>(luabind::globals(L)["Machine"]);
101 if (machine) {
102 return machine->system().Regname();
103 } else {
104 throw std::logic_error("No machine!?");
105 }
106 }
107
SetDecisionList(luabind::object table)108 void ScriptWorld::SetDecisionList(luabind::object table) {
109 decisions_.clear();
110 for (luabind::iterator itr(table), end; itr != end; ++itr) {
111 boost::optional<std::string> v = object_cast_nothrow<std::string>(*itr);
112
113 if (v) {
114 decisions_.push_back(*v);
115 }
116 }
117
118 ScriptMachine* machine =
119 luabind::object_cast<ScriptMachine*>(luabind::globals(L)["Machine"]);
120 if (machine) {
121 machine->SetDecisionList(decisions_);
122 }
123 }
124
Error(const std::string & error_message)125 void ScriptWorld::Error(const std::string& error_message) {
126 ScriptMachine* machine =
127 luabind::object_cast<ScriptMachine*>(luabind::globals(L)["Machine"]);
128 if (machine)
129 machine->Halt();
130
131 cerr << "ERROR: " << error_message << endl;
132 }
133
AddHandler(int scene,int lineNo,luabind::object handler)134 void ScriptWorld::AddHandler(int scene, int lineNo, luabind::object handler) {
135 ScriptMachine* machine =
136 luabind::object_cast<ScriptMachine*>(luabind::globals(L)["Machine"]);
137 if (machine) {
138 machine->AddLineAction(
139 scene, lineNo, boost::bind(&ScriptWorld::RunHandler, handler));
140 }
141 }
142
SetDecisionHandler(luabind::object obj)143 void ScriptWorld::SetDecisionHandler(luabind::object obj) {
144 luabind::globals(L)["DecisionHandler"] = obj;
145 }
146
MakeDecision(const std::vector<std::string> & decisions)147 std::string ScriptWorld::MakeDecision(
148 const std::vector<std::string>& decisions) {
149 luabind::object handler = luabind::globals(L)["DecisionHandler"];
150
151 if (type(handler) == LUA_TFUNCTION) {
152 object table = newtable(L);
153 for (int i = 0; i < decisions.size(); ++i) {
154 settable(table, i, decisions[i]);
155 }
156
157 luabind::object ret = handler(table);
158 if (type(ret) == LUA_TSTRING) {
159 return object_cast<std::string>(ret);
160 }
161 }
162
163 return "";
164 }
165
InitializeMachine(ScriptMachine & machine)166 void ScriptWorld::InitializeMachine(ScriptMachine& machine) {
167 luabind::globals(L)["Machine"] = &machine;
168 luabind::globals(L)["System"] = &(machine.system());
169 }
170
171 // static
InitializeLuabind(lua_State * L)172 void ScriptWorld::InitializeLuabind(lua_State* L) {
173 using namespace luabind;
174
175 open(L);
176 module(L)[
177 // High level interface
178 class_<ScriptWorld>("World")
179 .def("import", &ScriptWorld::Import)
180 .def("regname", &ScriptWorld::Regname)
181 .def("setDecisionList", &ScriptWorld::SetDecisionList)
182 .def("error", &ScriptWorld::Error)
183 .def("addHandler", &ScriptWorld::AddHandler)
184 .def("setDecisionHandler", &ScriptWorld::SetDecisionHandler),
185 register_utility(),
186 register_machine(),
187 register_system(),
188 register_event_system(),
189 register_graphics_system(),
190 register_graphics_object()
191 ];
192 }
193
194 // static
RunHandler(luabind::object handler)195 void ScriptWorld::RunHandler(luabind::object handler) {
196 try {
197 luabind::call_function<void>(handler);
198 }
199 catch (const luabind::error& e) {
200 lua_State* state = e.state();
201 std::cerr << lua_tostring(state, -1) << endl;
202 }
203 }
204