summary refs log tree commit diff stats
path: root/src/systems/scripting.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/systems/scripting.cpp')
-rw-r--r--src/systems/scripting.cpp219
1 files changed, 219 insertions, 0 deletions
diff --git a/src/systems/scripting.cpp b/src/systems/scripting.cpp new file mode 100644 index 0000000..dc1fff5 --- /dev/null +++ b/src/systems/scripting.cpp
@@ -0,0 +1,219 @@
1#include "scripting.h"
2#include "game.h"
3#include "components/runnable.h"
4#include "components/ponderable.h"
5#include "components/realizable.h"
6#include "components/transformable.h"
7#include "components/playable.h"
8#include "components/mappable.h"
9#include "components/prototypable.h"
10#include "systems/realizing.h"
11#include "vector.h"
12
13struct script_entity {
14 using id_type = EntityManager::id_type;
15
16 id_type id;
17
18 script_entity(id_type id) : id(id)
19 {
20 }
21};
22
23ScriptingSystem::ScriptingSystem(Game& game) : System(game)
24{
25 id_type entity = game_.getEntityManager().emplaceEntity();
26
27 engine.open_libraries(sol::lib::base, sol::lib::coroutine);
28
29 engine.new_usertype<vec2d>(
30 "vec2d",
31 sol::constructors<vec2d(), vec2d(double, double)>(),
32 "x", sol::property(
33 [] (vec2d& v) -> double { return v.x(); },
34 [] (vec2d& v, double x) { v.x() = x; }),
35 "y", sol::property(
36 [] (vec2d& v) -> double { return v.y(); },
37 [] (vec2d& v, double y) { v.y() = y; }));
38
39 engine.new_usertype<vec2i>(
40 "vec2i",
41 sol::constructors<vec2i(), vec2i(int, int)>(),
42 "x", [] (vec2i& v) -> int& { return v.x(); },
43 "y", [] (vec2i& v) -> int& { return v.y(); });
44
45 engine.new_usertype<script_entity>(
46 "entity",
47 sol::constructors<script_entity(id_type)>(),
48 "id", &script_entity::id,
49 "transformable",
50 [&] (script_entity& entity) -> TransformableComponent& {
51 return game_.getEntityManager().
52 getComponent<TransformableComponent>(entity.id);
53 },
54 "ponderable",
55 [&] (script_entity& entity) -> PonderableComponent& {
56 return game_.getEntityManager().
57 getComponent<PonderableComponent>(entity.id);
58 },
59 "mappable",
60 [&] (script_entity& entity) -> MappableComponent& {
61 return game_.getEntityManager().
62 getComponent<MappableComponent>(entity.id);
63 },
64 "playable",
65 [&] (script_entity& entity) -> PlayableComponent& {
66 return game_.getEntityManager().
67 getComponent<PlayableComponent>(entity.id);
68 },
69 "realizable",
70 [&] (script_entity& entity) -> RealizableComponent& {
71 return game_.getEntityManager().
72 getComponent<RealizableComponent>(entity.id);
73 },
74 "prototypable",
75 [&] (script_entity& entity) -> PrototypableComponent& {
76 return game_.getEntityManager().
77 getComponent<PrototypableComponent>(entity.id);
78 });
79
80 engine.new_usertype<TransformableComponent>(
81 "transformable",
82 "pos", &TransformableComponent::pos);
83
84 engine.new_usertype<PonderableComponent>(
85 "ponderable",
86 "vel", &PonderableComponent::vel,
87 "accel", &PonderableComponent::accel);
88
89 engine.new_usertype<MappableComponent>(
90 "mappable",
91 "mapId", &MappableComponent::mapId);
92
93 engine.new_usertype<PlayableComponent>(
94 "playable",
95 "checkpointPos", &PlayableComponent::checkpointPos,
96 "checkpointMapId", &PlayableComponent::checkpointMapId,
97 "checkpointMapObject", &PlayableComponent::checkpointMapObject,
98 "checkpointMapObjectIndex", &PlayableComponent::checkpointMapObjectIndex);
99
100 engine.new_usertype<RealizableComponent>(
101 "realizable",
102 "activeMap", &RealizableComponent::activeMap);
103
104 engine.new_usertype<PrototypableComponent>(
105 "prototypable",
106 "mapObjectIndex", &PrototypableComponent::mapObjectIndex,
107 "prototypeId", &PrototypableComponent::prototypeId);
108
109 engine.new_usertype<RealizingSystem>(
110 "realizing",
111 "singleton",
112 [&] (RealizingSystem& realizing) -> script_entity {
113 return realizing.getSingleton();
114 });
115
116 engine.set_function(
117 "realizing",
118 [&] () {
119 return game_.getSystemManager().getSystem<RealizingSystem>();
120 });
121
122 engine.script_file("scripts/common.lua");
123 engine.script_file("scripts/movplat.lua");
124 engine.script_file("scripts/checkpoint.lua");
125}
126
127void ScriptingSystem::tick(double dt)
128{
129 auto entities = game_.getEntityManager().getEntitiesWithComponents<
130 RunnableComponent>();
131
132 for (id_type entity : entities)
133 {
134 auto& runnable = game_.getEntityManager().
135 getComponent<RunnableComponent>(entity);
136
137 if (*runnable.callable)
138 {
139 auto result = (*runnable.callable)(dt);
140 if (!result.valid())
141 {
142 sol::error e = result;
143 throw std::runtime_error(e.what());
144 }
145 }
146
147 if (!*runnable.callable)
148 {
149 game_.getEntityManager().deleteEntity(entity);
150 }
151 }
152}
153
154void ScriptingSystem::killScript(id_type entity)
155{
156 if (game_.getEntityManager().hasComponent<RunnableComponent>(entity))
157 {
158 game_.getEntityManager().deleteEntity(entity);
159 }
160}
161
162template <typename... Args>
163EntityManager::id_type ScriptingSystem::runScript(
164 std::string event,
165 id_type entity,
166 Args&&... args)
167{
168 auto& prototypable = game_.getEntityManager().
169 getComponent<PrototypableComponent>(entity);
170
171 id_type script = game_.getEntityManager().emplaceEntity();
172
173 auto& runnable = game_.getEntityManager().
174 emplaceComponent<RunnableComponent>(script);
175
176 runnable.runner =
177 std::unique_ptr<sol::thread>(
178 new sol::thread(
179 sol::thread::create(
180 engine.lua_state())));
181
182 runnable.callable =
183 std::unique_ptr<sol::coroutine>(
184 new sol::coroutine(
185 runnable.runner->state().
186 traverse_get<sol::function>(
187 prototypable.prototypeId,
188 event)));
189
190 if (!*runnable.callable)
191 {
192 throw std::runtime_error("Error running script");
193 }
194
195 auto result = (*runnable.callable)(
196 script_entity(entity),
197 std::forward<Args>(args)...);
198
199 if (!result.valid())
200 {
201 sol::error e = result;
202 throw std::runtime_error(e.what());
203 }
204
205 return script;
206}
207
208EntityManager::id_type ScriptingSystem::runBehaviorScript(id_type entity)
209{
210 return runScript("Behavior", entity);
211}
212
213void ScriptingSystem::onTouch(id_type entity, id_type player)
214{
215 runScript(
216 "OnTouch",
217 entity,
218 script_entity(player));
219}