Add documentation on placing tiles.
[Tsunagari.git] / src / scriptinst.cpp
blob261816d46be4b26c2b9a499986dd15289efa5ba3
1 /*********************************
2 ** Tsunagari Tile Engine **
3 ** scriptinst.cpp **
4 ** Copyright 2011-2012 OmegaSDG **
5 *********************************/
7 // **********
8 // Permission is hereby granted, free of charge, to any person obtaining a copy
9 // of this software and associated documentation files (the "Software"), to
10 // deal in the Software without restriction, including without limitation the
11 // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
12 // sell copies of the Software, and to permit persons to whom the Software is
13 // furnished to do so, subject to the following conditions:
15 // The above copyright notice and this permission notice shall be included in
16 // all copies or substantial portions of the Software.
18 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
24 // IN THE SOFTWARE.
25 // **********
27 #include "log.h"
28 #include "python.h"
29 #include "resourcer.h"
30 #include "scriptinst.h"
32 struct validate_visitor : public boost::static_visitor<bool>
34 std::string context;
36 validate_visitor(const std::string& context) : context(context) {}
38 bool operator()(void*) const
40 return true;
43 bool operator()(ScriptInst::strref ref) const
45 Resourcer* rc = Resourcer::instance();
47 if (ref.filename.empty()) {
48 Log::err(context,
49 "script filename is empty");
50 return false;
53 if (!rc->resourceExists(ref.filename)) {
54 Log::err(context,
55 ref.filename + "script file not found");
56 return false;
59 return true;
62 bool operator()(boost::python::object) const
64 return true;
68 struct invoke_visitor : public boost::static_visitor<bool>
70 bool operator()(void*) const
72 return true;
75 bool operator()(ScriptInst::strref ref) const
77 Resourcer* rc = Resourcer::instance();
79 if (ref.funcname.size()) {
80 rc->runPythonScript(ref.filename);
81 return pythonExec(ref.funccall);
83 else {
84 return rc->runPythonScript(ref.filename);
88 bool operator()(boost::python::object pyfn) const
90 try {
91 inPythonScript++;
92 pyfn();
93 inPythonScript--;
94 return true;
95 } catch (boost::python::error_already_set) {
96 inPythonScript--;
97 pythonErr();
98 return false;
103 ScriptInst::ScriptInst()
104 : data((void*)NULL)
108 ScriptInst::ScriptInst(const std::string& strloc)
110 size_t colon = strloc.find(':');
111 strref ref;
112 if (colon == std::string::npos) {
113 ref.filename = strloc;
115 else {
116 ref.filename = strloc.substr(0, colon);
117 ref.funcname = strloc.substr(colon + 1);
118 ref.funccall = pythonCompile(
119 "<Tsunagari trigger>",
120 (ref.funcname).c_str()
123 data = ref;
126 ScriptInst::ScriptInst(boost::python::object pyfn)
127 : data(pyfn)
131 bool ScriptInst::validate(const std::string& context)
133 return boost::apply_visitor(validate_visitor(context), data);
136 bool ScriptInst::invoke()
138 return boost::apply_visitor(invoke_visitor(), data);
148 struct topython_visitor : public boost::static_visitor<PyObject*>
150 PyObject* operator()(void*) const
152 using namespace boost::python;
154 return incref(Py_None);
157 PyObject* operator()(ScriptInst::strref ref) const
159 using namespace boost::python;
161 // Prevent compilation name collisions with "object" by making
162 // it "bp::object".
163 namespace bp = boost::python;
165 bp::object str;
166 if (ref.funcname.size())
167 str = bp::object(ref.filename + ":" + ref.funcname);
168 else
169 str = bp::object(ref.filename);
170 return incref(str.ptr());
173 PyObject* operator()(boost::python::object pyfn) const
175 using namespace boost::python;
177 return incref(pyfn.ptr());
182 struct scriptinst_to_python
184 static PyObject* convert(ScriptInst script)
186 return boost::apply_visitor(topython_visitor(), script.data);
191 struct scriptinst_from_python
193 scriptinst_from_python()
195 boost::python::converter::registry::push_back(
196 &convertible,
197 &construct,
198 boost::python::type_id<ScriptInst>());
201 // Can this be converted to a ScriptInst?
202 static void* convertible(PyObject* obj)
204 // XXX: Return non-NULL only if string or
205 // callable (fn or lambda?).
206 return obj;
209 // Convert. boost::python provides us with a chunch of memory that we
210 // have to construct in-place.
211 static void construct(
212 PyObject* obj,
213 boost::python::converter::rvalue_from_python_stage1_data* data)
215 using namespace boost::python;
217 // Prevent compilation name collisions with "object" by making
218 // it "bp::object".
219 namespace bp = boost::python;
221 void* storage =
222 ((converter::rvalue_from_python_storage<ScriptInst>*)data)
223 ->storage.bytes;
225 if (PyString_Check(obj)) {
226 const char* value = PyString_AsString(obj);
227 new (storage) ScriptInst(value);
229 else {
230 // By default, the PyObject is a borrowed reference,
231 // which means it hasn't been incref'd.
232 handle<> hndl(borrowed(obj));
233 new (storage) ScriptInst(bp::object(hndl));
236 data->convertible = storage;
240 void exportScriptInst()
242 using namespace boost::python;
244 to_python_converter<ScriptInst, scriptinst_to_python>();
245 scriptinst_from_python();