summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorKelly Rauchenberger <fefferburbia@gmail.com>2018-05-14 18:40:54 -0400
committerKelly Rauchenberger <fefferburbia@gmail.com>2018-05-17 15:39:39 -0400
commit5e48cf6333aca7af6854d79194f138d57ce0b5e1 (patch)
treeb1703c6268b762a04a101f35188163fe2d9feb45
parent046ee24a341468e9b3ea2983a731dbce18b52ac6 (diff)
downloadtherapy-5e48cf6333aca7af6854d79194f138d57ce0b5e1.tar.gz
therapy-5e48cf6333aca7af6854d79194f138d57ce0b5e1.tar.bz2
therapy-5e48cf6333aca7af6854d79194f138d57ce0b5e1.zip
Specialized treatment of behavior scripts
The AutomatableComponent now links to the Runnable entity representing the behavior script.

Also reordered the SystemManager and EntityManager members of the Game class such that the EntityManager is destroyed before the SystemManager is. This fixes a bug where the destruction of a component has some affect on the state of a system. Specifically, if the ScriptingSystem (and thus the Lua state) is destroyed before the EntityManager is and there are any Runnable entities, the game will crash when trying to destroy them.
-rw-r--r--src/components/automatable.h34
-rw-r--r--src/components/prototypable.h11
-rw-r--r--src/components/runnable.h36
-rw-r--r--src/game.h2
-rw-r--r--src/systems/realizing.cpp33
-rw-r--r--src/systems/scripting.cpp70
-rw-r--r--src/systems/scripting.h10
7 files changed, 153 insertions, 43 deletions
diff --git a/src/components/automatable.h b/src/components/automatable.h new file mode 100644 index 0000000..22d9859 --- /dev/null +++ b/src/components/automatable.h
@@ -0,0 +1,34 @@
1#ifndef AUTOMATABLE_H_FACB42A5
2#define AUTOMATABLE_H_FACB42A5
3
4#include "component.h"
5#include "entity_manager.h"
6
7class AutomatableComponent : public Component {
8public:
9
10 using id_type = EntityManager::id_type;
11
12 /**
13 * Controls what script will be run as this entity's behavior. It should refer
14 * to a table in the global namespace of the script engine state, and that
15 * table should contain a function called "Behavior".
16 */
17 std::string table;
18
19 /**
20 * Whether or not the behavior script is running.
21 *
22 * @managed_by ScriptingSystem
23 */
24 bool running = false;
25
26 /**
27 * The entity ID of the running script, if there is one.
28 *
29 * @managed_by ScriptingSystem
30 */
31 id_type script;
32};
33
34#endif /* end of include guard: AUTOMATABLE_H_FACB42A5 */
diff --git a/src/components/prototypable.h b/src/components/prototypable.h index 4659e7c..c0dd972 100644 --- a/src/components/prototypable.h +++ b/src/components/prototypable.h
@@ -9,14 +9,15 @@ public:
9 9
10 using id_type = EntityManager::id_type; 10 using id_type = EntityManager::id_type;
11 11
12 /**
13 * The index of the object in the map definition.
14 */
12 size_t mapObjectIndex; 15 size_t mapObjectIndex;
13 16
17 /**
18 * The name of the prototype that the object was spawned from.
19 */
14 std::string prototypeId; 20 std::string prototypeId;
15
16 bool hasBehavior = false;
17 bool runningBehavior = false;
18
19 id_type behaviorScript;
20}; 21};
21 22
22#endif /* end of include guard: PROTOTYPABLE_H_817F2205 */ 23#endif /* end of include guard: PROTOTYPABLE_H_817F2205 */
diff --git a/src/components/runnable.h b/src/components/runnable.h index 1b994fb..956bfdc 100644 --- a/src/components/runnable.h +++ b/src/components/runnable.h
@@ -4,12 +4,48 @@
4#include "component.h" 4#include "component.h"
5#include <sol.hpp> 5#include <sol.hpp>
6#include <memory> 6#include <memory>
7#include "entity_manager.h"
7 8
8class RunnableComponent : public Component { 9class RunnableComponent : public Component {
9public: 10public:
10 11
12 using id_type = EntityManager::id_type;
13
14 /**
15 * A Lua stack where the entity's script is running.
16 *
17 * NOTE: This object is called a thread, but there is no multi-threading going
18 * on.
19 *
20 * @managed_by ScriptingSystem
21 */
11 std::unique_ptr<sol::thread> runner; 22 std::unique_ptr<sol::thread> runner;
23
24 /**
25 * An entry point to the script running in the runner thread.
26 *
27 * @managed_by ScriptingSystem
28 */
12 std::unique_ptr<sol::coroutine> callable; 29 std::unique_ptr<sol::coroutine> callable;
30
31 /**
32 * Whether or not this entity represents a behavior script. A behavior script
33 * usually does not terminate on its own, and can be terminated at will by
34 * another system, usually when the automatable entity leaves the active map.
35 *
36 * @managed_by ScriptingSystem
37 */
38 bool behavior = false;
39
40 /**
41 * If this is a behavior script, this is the ID of the automatable entity that
42 * the behavior belongs to. This is required so that the ScriptingSystem can
43 * notify the automatable entity if the behavior script terminates by itself,
44 * and that it shouldn't attempt to terminate it.
45 *
46 * @managed_by ScriptingSystem
47 */
48 id_type actor;
13}; 49};
14 50
15#endif /* end of include guard: AUTOMATABLE_H_3D519131 */ 51#endif /* end of include guard: AUTOMATABLE_H_3D519131 */
diff --git a/src/game.h b/src/game.h index dc256c6..d7fdcd7 100644 --- a/src/game.h +++ b/src/game.h
@@ -44,8 +44,8 @@ private:
44 44
45 std::mt19937 rng_; 45 std::mt19937 rng_;
46 Renderer renderer_; 46 Renderer renderer_;
47 EntityManager entityManager_;
48 SystemManager systemManager_; 47 SystemManager systemManager_;
48 EntityManager entityManager_;
49 bool shouldQuit_ = false; 49 bool shouldQuit_ = false;
50}; 50};
51 51
diff --git a/src/systems/realizing.cpp b/src/systems/realizing.cpp index 7f5aefb..baacf5a 100644 --- a/src/systems/realizing.cpp +++ b/src/systems/realizing.cpp
@@ -12,6 +12,7 @@
12#include "components/ponderable.h" 12#include "components/ponderable.h"
13#include "components/transformable.h" 13#include "components/transformable.h"
14#include "components/prototypable.h" 14#include "components/prototypable.h"
15#include "components/automatable.h"
15#include "systems/mapping.h" 16#include "systems/mapping.h"
16#include "systems/animating.h" 17#include "systems/animating.h"
17#include "systems/pondering.h" 18#include "systems/pondering.h"
@@ -223,7 +224,10 @@ RealizingSystem::RealizingSystem(
223 224
224 if (prototypeId == "movplat") 225 if (prototypeId == "movplat")
225 { 226 {
226 prototypable.hasBehavior = true; 227 auto& automatable = game_.getEntityManager().
228 emplaceComponent<AutomatableComponent>(mapObject);
229
230 automatable.table = prototypeId;
227 } else if (prototypeId == "checkpoint") 231 } else if (prototypeId == "checkpoint")
228 { 232 {
229 auto& ponderable = game_.getEntityManager(). 233 auto& ponderable = game_.getEntityManager().
@@ -403,19 +407,9 @@ void RealizingSystem::enterActiveMap(id_type entity)
403 ponderable.active = true; 407 ponderable.active = true;
404 } 408 }
405 409
406 if (game_.getEntityManager().hasComponent<PrototypableComponent>(entity)) 410 if (game_.getEntityManager().hasComponent<AutomatableComponent>(entity))
407 { 411 {
408 auto& prototypable = game_.getEntityManager(). 412 game_.getSystemManager().getSystem<ScriptingSystem>().startBehavior(entity);
409 getComponent<PrototypableComponent>(entity);
410
411 if (prototypable.hasBehavior)
412 {
413 auto& scripting = game_.getSystemManager().getSystem<ScriptingSystem>();
414
415 prototypable.hasBehavior = true;
416 prototypable.runningBehavior = true;
417 prototypable.behaviorScript = scripting.runBehaviorScript(entity);
418 }
419 } 413 }
420} 414}
421 415
@@ -437,17 +431,8 @@ void RealizingSystem::leaveActiveMap(id_type entity)
437 ponderable.active = false; 431 ponderable.active = false;
438 } 432 }
439 433
440 if (game_.getEntityManager().hasComponent<PrototypableComponent>(entity)) 434 if (game_.getEntityManager().hasComponent<AutomatableComponent>(entity))
441 { 435 {
442 auto& prototypable = game_.getEntityManager(). 436 game_.getSystemManager().getSystem<ScriptingSystem>().stopBehavior(entity);
443 getComponent<PrototypableComponent>(entity);
444
445 if (prototypable.runningBehavior)
446 {
447 auto& scripting = game_.getSystemManager().getSystem<ScriptingSystem>();
448 scripting.killScript(prototypable.behaviorScript);
449
450 prototypable.runningBehavior = false;
451 }
452 } 437 }
453} 438}
diff --git a/src/systems/scripting.cpp b/src/systems/scripting.cpp index 57c3fd5..c423558 100644 --- a/src/systems/scripting.cpp +++ b/src/systems/scripting.cpp
@@ -6,6 +6,7 @@
6#include "components/playable.h" 6#include "components/playable.h"
7#include "components/mappable.h" 7#include "components/mappable.h"
8#include "components/prototypable.h" 8#include "components/prototypable.h"
9#include "components/automatable.h"
9#include "systems/realizing.h" 10#include "systems/realizing.h"
10#include "vector.h" 11#include "vector.h"
11 12
@@ -133,28 +134,34 @@ void ScriptingSystem::tick(double dt)
133 134
134 if (!*runnable.callable) 135 if (!*runnable.callable)
135 { 136 {
136 game_.getEntityManager().deleteEntity(entity); 137 killScript(entity);
137 } 138 }
138 } 139 }
139} 140}
140 141
141void ScriptingSystem::killScript(id_type entity) 142void ScriptingSystem::killScript(id_type entity)
142{ 143{
143 if (game_.getEntityManager().hasComponent<RunnableComponent>(entity)) 144 auto& runnable = game_.getEntityManager().
145 getComponent<RunnableComponent>(entity);
146
147 if (runnable.behavior)
144 { 148 {
145 game_.getEntityManager().deleteEntity(entity); 149 auto& automatable = game_.getEntityManager().
150 getComponent<AutomatableComponent>(runnable.actor);
151
152 automatable.running = false;
146 } 153 }
154
155 game_.getEntityManager().deleteEntity(entity);
147} 156}
148 157
149template <typename... Args> 158template <typename... Args>
150EntityManager::id_type ScriptingSystem::runScript( 159sol::optional<EntityManager::id_type> ScriptingSystem::runScript(
160 std::string table,
151 std::string event, 161 std::string event,
152 id_type entity, 162 id_type entity,
153 Args&&... args) 163 Args&&... args)
154{ 164{
155 auto& prototypable = game_.getEntityManager().
156 getComponent<PrototypableComponent>(entity);
157
158 id_type script = game_.getEntityManager().emplaceEntity(); 165 id_type script = game_.getEntityManager().emplaceEntity();
159 166
160 auto& runnable = game_.getEntityManager(). 167 auto& runnable = game_.getEntityManager().
@@ -171,7 +178,7 @@ EntityManager::id_type ScriptingSystem::runScript(
171 new sol::coroutine( 178 new sol::coroutine(
172 runnable.runner->state(). 179 runnable.runner->state().
173 traverse_get<sol::function>( 180 traverse_get<sol::function>(
174 prototypable.prototypeId, 181 table,
175 event))); 182 event)));
176 183
177 if (!*runnable.callable) 184 if (!*runnable.callable)
@@ -189,17 +196,58 @@ EntityManager::id_type ScriptingSystem::runScript(
189 throw std::runtime_error(e.what()); 196 throw std::runtime_error(e.what());
190 } 197 }
191 198
192 return script; 199 if (*runnable.callable)
200 {
201 return { script };
202 } else {
203 killScript(script);
204
205 return {};
206 }
207}
208
209void ScriptingSystem::startBehavior(id_type entity)
210{
211 auto& automatable = game_.getEntityManager().
212 getComponent<AutomatableComponent>(entity);
213
214 sol::optional<id_type> script =
215 runScript(
216 automatable.table,
217 "Behavior",
218 entity);
219
220 if (script)
221 {
222 automatable.script = *script;
223 automatable.running = true;
224
225 auto& runnable = game_.getEntityManager().
226 getComponent<RunnableComponent>(automatable.script);
227
228 runnable.behavior = true;
229 runnable.actor = entity;
230 }
193} 231}
194 232
195EntityManager::id_type ScriptingSystem::runBehaviorScript(id_type entity) 233void ScriptingSystem::stopBehavior(id_type entity)
196{ 234{
197 return runScript("Behavior", entity); 235 auto& automatable = game_.getEntityManager().
236 getComponent<AutomatableComponent>(entity);
237
238 if (automatable.running)
239 {
240 killScript(automatable.script);
241 }
198} 242}
199 243
200void ScriptingSystem::onTouch(id_type entity, id_type player) 244void ScriptingSystem::onTouch(id_type entity, id_type player)
201{ 245{
246 auto& prototypable = game_.getEntityManager().
247 getComponent<PrototypableComponent>(entity);
248
202 runScript( 249 runScript(
250 prototypable.prototypeId,
203 "OnTouch", 251 "OnTouch",
204 entity, 252 entity,
205 script_entity(player)); 253 script_entity(player));
diff --git a/src/systems/scripting.h b/src/systems/scripting.h index e330316..b119c3f 100644 --- a/src/systems/scripting.h +++ b/src/systems/scripting.h
@@ -13,14 +13,20 @@ public:
13 13
14 void killScript(id_type entity); 14 void killScript(id_type entity);
15 15
16 id_type runBehaviorScript(id_type entity); 16 void startBehavior(id_type entity);
17
18 void stopBehavior(id_type entity);
17 19
18 void onTouch(id_type entity, id_type player); 20 void onTouch(id_type entity, id_type player);
19 21
20private: 22private:
21 23
22 template <typename... Args> 24 template <typename... Args>
23 id_type runScript(std::string event, id_type entity, Args&&... args); 25 sol::optional<id_type> runScript(
26 std::string table,
27 std::string event,
28 id_type entity,
29 Args&&... args);
24 30
25 sol::state engine_; 31 sol::state engine_;
26}; 32};