载入中...
搜索中...
未找到
ReflectScript.cpp
浏览该文件的文档.
2
3#include "common/Runtime.h"
4
5#include <simplesquirrel/simplesquirrel.hpp>
6
7#include <cstddef>
8#include <string>
9
10namespace eve {
11namespace {
12
13const char* scriptStateName(ScriptState state) {
14 switch (state) {
15 case ScriptState::Compiled: return "Compiled";
16 case ScriptState::Running: return "Running";
17 case ScriptState::Loaded: return "Loaded";
18 case ScriptState::Unloading: return "Unloading";
19 case ScriptState::Unloaded: return "Unloaded";
20 case ScriptState::Failed: return "Failed";
21 }
22 return "Unknown";
23}
24
26ssq::Object objectFromTop(HSQUIRRELVM vm, SQInteger top) {
27 ssq::Object out(vm);
28 sq_getstackobj(vm, -1, &out.getRaw());
29 sq_addref(vm, &out.getRaw());
30 sq_settop(vm, top);
31 return out;
32}
33
35ssq::Object nullObject(HSQUIRRELVM vm) { return ssq::Object(vm); }
36
38ssq::Object readMemberValue(const ssq::Object& instance, const std::string& name) {
39 if (instance.getType() != ssq::Type::INSTANCE || name.empty()) return nullObject(instance.getHandle());
40 HSQUIRRELVM vm = instance.getHandle();
41 const SQInteger top = sq_gettop(vm);
42 sq_pushobject(vm, instance.getRaw());
43 sq_pushstring(vm, name.c_str(), static_cast<SQInteger>(name.size()));
44 if (SQ_FAILED(sq_get(vm, -2))) {
45 sq_settop(vm, top);
46 return nullObject(vm);
47 }
48 return objectFromTop(vm, top);
49}
50
52ssq::Object readArrayElement(const ssq::Object& instance, const std::string& name, size_t index) {
53 if (instance.getType() != ssq::Type::INSTANCE || name.empty()) return nullObject(instance.getHandle());
54 HSQUIRRELVM vm = instance.getHandle();
55 const SQInteger top = sq_gettop(vm);
56 sq_pushobject(vm, instance.getRaw());
57 sq_pushstring(vm, name.c_str(), static_cast<SQInteger>(name.size()));
58 if (SQ_FAILED(sq_get(vm, -2)) || sq_gettype(vm, -1) != OT_ARRAY) {
59 sq_settop(vm, top);
60 return nullObject(vm);
61 }
62 sq_pushinteger(vm, static_cast<SQInteger>(index));
63 if (SQ_FAILED(sq_get(vm, -2))) {
64 sq_settop(vm, top);
65 return nullObject(vm);
66 }
67 return objectFromTop(vm, top);
68}
69
71ssq::Object readTableValue(const ssq::Object& instance, const std::string& name, const std::string& key) {
72 if (instance.getType() != ssq::Type::INSTANCE || name.empty()) return nullObject(instance.getHandle());
73 HSQUIRRELVM vm = instance.getHandle();
74 const SQInteger top = sq_gettop(vm);
75 sq_pushobject(vm, instance.getRaw());
76 sq_pushstring(vm, name.c_str(), static_cast<SQInteger>(name.size()));
77 if (SQ_FAILED(sq_get(vm, -2)) || sq_gettype(vm, -1) != OT_TABLE) {
78 sq_settop(vm, top);
79 return nullObject(vm);
80 }
81 sq_pushstring(vm, key.c_str(), static_cast<SQInteger>(key.size()));
82 if (SQ_FAILED(sq_get(vm, -2))) {
83 sq_settop(vm, top);
84 return nullObject(vm);
85 }
86 return objectFromTop(vm, top);
87}
88
93bool convertScalar(const ssq::Object& value, ReflectedValue& out) {
94 switch (value.getType()) {
95 case ssq::Type::BOOL:
96 out.kind = ReflectedValueKind::Bool;
97 out.boolean = value.toBool();
98 return true;
99 case ssq::Type::INTEGER:
100 out.kind = ReflectedValueKind::Integer;
101 out.integer = value.toInt();
102 return true;
103 case ssq::Type::FLOAT:
104 out.kind = ReflectedValueKind::Float;
105 out.floating = value.toFloat();
106 return true;
107 case ssq::Type::STRING:
108 out.kind = ReflectedValueKind::String;
109 out.text = value.toString();
110 return true;
111 default: return false;
112 }
113}
114
116ssq::Table memberTable(ssq::VM& vm, const ReflectedMember& member, const ssq::Object* instance) {
117 ssq::Table out = vm.newTable();
118 out.set("name", member.name);
119 out.set("type", std::string(ssq::typeToStr(member.type)));
120 out.set("method", member.method);
121
122 ssq::Table attributes = vm.newTable();
123 for (const ReflectedAttribute& attribute : member.attributes)
124 attributes.set(attribute.name.c_str(), attribute.value);
125 out.set("attributes", attributes);
126
127 if (instance && !member.method)
128 out.set("value", readMemberValue(*instance, member.name));
129 else
130 out.set("value", nullObject(vm.getHandle()));
131 return out;
132}
133
135ssq::Table classTable(ssq::VM& vm, const ReflectedClass& cls) {
136 ssq::Table out = vm.newTable();
137 out.set("name", cls.name);
138 out.set("source", cls.source);
139 out.set("base", cls.base);
140
141 ssq::Array members = vm.newArray();
142 for (const ReflectedMember& member : cls.members) members.push(memberTable(vm, member, nullptr));
143 out.set("members", members);
144 return out;
145}
146
148ssq::Table scriptInfoTable(ssq::VM& vm, const ScriptInfo& info) {
149 ssq::Table out = vm.newTable();
150 out.set("id", static_cast<int>(info.id));
151 out.set("source", info.source);
152 out.set("state", std::string(scriptStateName(info.state)));
153 out.set("error", info.error);
154
155 ssq::Array classes = vm.newArray();
156 for (const std::string& name : info.classes) classes.push(name);
157 out.set("classes", classes);
158 return out;
159}
160
161} // namespace
162
163void exposeReflection(Runtime& runtime, ssq::Table eveTable) {
164 ssq::Table reflect = eveTable.addTable("reflect");
165
166 reflect.addFunc("classes", [&runtime]() {
167 ssq::Table out = runtime.vm().newTable();
168 for (const ReflectedClass& cls : runtime.reflectedClasses())
169 out.set(cls.name.c_str(), classTable(runtime.vm(), cls));
170 return out;
171 });
172
173 reflect.addFunc("classInfo", [&runtime](std::string name) -> ssq::Object {
174 const ReflectedClass* cls = runtime.reflectedClass(name);
175 if (!cls) return nullObject(runtime.handle());
176 return classTable(runtime.vm(), *cls);
177 });
178
179 reflect.addFunc("scan", [&runtime]() { return static_cast<int>(runtime.scanClasses()); });
180
181 reflect.addFunc("createInstance", [&runtime](std::string name) { return runtime.createInstance(name); });
182
183 reflect.addFunc("classNameOf", [&runtime](const ssq::Object& instance) { return runtime.classNameOf(instance); });
184
185 reflect.addFunc("inspect", [&runtime](const ssq::Object& instance) {
186 ssq::Array out = runtime.vm().newArray();
187 if (instance.getType() != ssq::Type::INSTANCE) return out;
188 for (const ReflectedMember& member : runtime.reflectInstance(instance))
189 out.push(memberTable(runtime.vm(), member, &instance));
190 return out;
191 });
192
193 reflect.addFunc("read",
194 [](const ssq::Object& instance, std::string name) { return readMemberValue(instance, name); });
195
196 reflect.addFunc("write", [&runtime](const ssq::Object& instance, std::string name, const ssq::Object& value) {
197 ReflectedValue converted;
198 if (!convertScalar(value, converted)) return false;
199 return runtime.writeProperty(instance, name, converted);
200 });
201
202 reflect.addFunc("readObject", [&runtime](const ssq::Object& instance, std::string name) {
203 return runtime.readObjectProperty(instance, name);
204 });
205
206 reflect.addFunc("arraySize", [&runtime](const ssq::Object& instance, std::string name) {
207 return static_cast<int>(runtime.arraySize(instance, name));
208 });
209
210 reflect.addFunc("arrayGet", [](const ssq::Object& instance, std::string name, int index) {
211 return readArrayElement(instance, name, static_cast<size_t>(index));
212 });
213
214 reflect.addFunc("arraySet",
215 [&runtime](const ssq::Object& instance, std::string name, int index, const ssq::Object& value) {
216 ReflectedValue converted;
217 if (!convertScalar(value, converted)) return false;
218 return runtime.arraySet(instance, name, static_cast<size_t>(index), converted);
219 });
220
221 reflect.addFunc("arrayAppend", [&runtime](const ssq::Object& instance, std::string name, const ssq::Object& value) {
222 ReflectedValue converted;
223 if (!convertScalar(value, converted)) return false;
224 return runtime.arrayAppend(instance, name, converted);
225 });
226
227 reflect.addFunc("arrayRemove", [&runtime](const ssq::Object& instance, std::string name, int index) {
228 return runtime.arrayRemove(instance, name, static_cast<size_t>(index));
229 });
230
231 reflect.addFunc("tableKeys", [&runtime](const ssq::Object& instance, std::string name) {
232 ssq::Array out = runtime.vm().newArray();
233 for (const std::string& key : runtime.tableKeys(instance, name)) out.push(key);
234 return out;
235 });
236
237 reflect.addFunc("tableGet", [](const ssq::Object& instance, std::string name, std::string key) {
238 return readTableValue(instance, name, key);
239 });
240
241 reflect.addFunc("tableSet", [&runtime](const ssq::Object& instance, std::string name, std::string key,
242 const ssq::Object& value) {
243 ReflectedValue converted;
244 if (!convertScalar(value, converted)) return false;
245 return runtime.tableSet(instance, name, key, converted);
246 });
247
248 reflect.addFunc("tableRemove", [&runtime](const ssq::Object& instance, std::string name, std::string key) {
249 return runtime.tableRemove(instance, name, key);
250 });
251
252 reflect.addFunc("scripts", [&runtime]() {
253 ssq::Array out = runtime.vm().newArray();
254 for (const ScriptInfo& info : runtime.scripts()) out.push(scriptInfoTable(runtime.vm(), info));
255 return out;
256 });
257}
258
259} // namespace eve
double value
SQInteger top
struct SQVM * HSQUIRRELVM
HSQUIRRELVM vm
Definition ECS.cpp:20
HSQOBJECT cls
Definition ECS.cpp:21
std::uint32_t key
std::string name
float(ui::Theme::* member)[4]
std::map< std::string, std::span< const std::uint8_t > > members
uint32_t index
EVENGINE_API_FOUNDATION public API.
Definition Runtime.h:189
Build metadata (engine git commit, build time, third-party version).
Definition Build.cpp:16
ScriptState
ScriptState public API.
Definition Runtime.h:42
void exposeReflection(Runtime &runtime, ssq::Table eveTable)
Exposes the Runtime reflection API to scripts as eve.reflect.
EVENGINE_API_FOUNDATION_INLINE public API.
Definition Runtime.h:172
EVENGINE_API_FOUNDATION public API.
Definition Runtime.h:152
Typed snapshot of one live instance property.
Definition Runtime.h:132
EVENGINE_API_FOUNDATION_INLINE public API.
Definition Runtime.h:180
glm::uvec4 info