diff options
author | Kelly Rauchenberger <fefferburbia@gmail.com> | 2018-05-13 00:50:11 -0400 |
---|---|---|
committer | Kelly Rauchenberger <fefferburbia@gmail.com> | 2018-05-17 15:39:39 -0400 |
commit | 5269e7c09a0b17c8c972c8ad996b04d42dbcd9cb (patch) | |
tree | 94a3f4ce0a0e54375cd2f27fb90d7c35295bda2e /src | |
parent | 59808c86bf0e4d5cf0b6ab3d6ed1d8bdcd303a37 (diff) | |
download | therapy-5269e7c09a0b17c8c972c8ad996b04d42dbcd9cb.tar.gz therapy-5269e7c09a0b17c8c972c8ad996b04d42dbcd9cb.tar.bz2 therapy-5269e7c09a0b17c8c972c8ad996b04d42dbcd9cb.zip |
Started event handlers
The AutomatingSystem has been renamed to the ScriptingSystem, since the automatic behavior script is just a special case of the scripts that an entity can exhibit. The AutomatableComponent has largely been moved to the new RunnableComponent (might not be the final name for it). The Lua state object, previously living on the singleton RealizableComponent, is now a member of the ScriptingSystem itself, because it A) doesn't really belong on the realizable entity, and B) a singleton entity seems weird and like a cumbersome attempt to apply the ECS rules to places they don't apply. In a similar vein, the RealizableComponent itself will probably soon be integrated into the RealizingSystem too. The attempt at using Lua environments in order to encapsulate the different behaviors that objects exhibit was scrapped in preference of just creating differently named Lua tables for each prototype. The new PrototypableComponent contains some information about entities which were prototyped. It is partially used by the ScriptingSystem to figure out what event handlers are appropriate, which may not be the best approach. It also has some data about automatic behavior, which also maybe does not belong in this component. The OnTouch event is raised by a player colliding with a physics body with the collider type "event", which may not be the best way to implement this. The result of all of this is that checkpoints now work, although no sound is played, and the result is not persistent across exiting the game.
Diffstat (limited to 'src')
-rw-r--r-- | src/components/automatable.h | 25 | ||||
-rw-r--r-- | src/components/playable.h | 3 | ||||
-rw-r--r-- | src/components/ponderable.h | 3 | ||||
-rw-r--r-- | src/components/prototypable.h | 22 | ||||
-rw-r--r-- | src/components/realizable.h | 3 | ||||
-rw-r--r-- | src/components/runnable.h | 15 | ||||
-rw-r--r-- | src/game.cpp | 4 | ||||
-rw-r--r-- | src/systems/automating.cpp | 106 | ||||
-rw-r--r-- | src/systems/automating.h | 22 | ||||
-rw-r--r-- | src/systems/pondering.cpp | 13 | ||||
-rw-r--r-- | src/systems/realizing.cpp | 66 | ||||
-rw-r--r-- | src/systems/scripting.cpp | 219 | ||||
-rw-r--r-- | src/systems/scripting.h | 28 |
13 files changed, 346 insertions, 183 deletions
diff --git a/src/components/automatable.h b/src/components/automatable.h deleted file mode 100644 index d30340a..0000000 --- a/src/components/automatable.h +++ /dev/null | |||
@@ -1,25 +0,0 @@ | |||
1 | #ifndef AUTOMATABLE_H_3D519131 | ||
2 | #define AUTOMATABLE_H_3D519131 | ||
3 | |||
4 | #include "component.h" | ||
5 | #include <sol.hpp> | ||
6 | #include <memory> | ||
7 | |||
8 | class AutomatableComponent : public Component { | ||
9 | public: | ||
10 | |||
11 | std::unique_ptr<sol::thread> runner; | ||
12 | std::unique_ptr<sol::coroutine> behavior; | ||
13 | |||
14 | sol::environment origBehavior; | ||
15 | |||
16 | /** | ||
17 | * If this flag is disabled, the entity will be ignored by the automating | ||
18 | * system. | ||
19 | * | ||
20 | * @managed_by RealizingSystem | ||
21 | */ | ||
22 | bool active = false; | ||
23 | }; | ||
24 | |||
25 | #endif /* end of include guard: AUTOMATABLE_H_3D519131 */ | ||
diff --git a/src/components/playable.h b/src/components/playable.h index b8af0f2..7404f1f 100644 --- a/src/components/playable.h +++ b/src/components/playable.h | |||
@@ -27,6 +27,9 @@ public: | |||
27 | size_t checkpointMapId; | 27 | size_t checkpointMapId; |
28 | vec2d checkpointPos; | 28 | vec2d checkpointPos; |
29 | 29 | ||
30 | bool checkpointMapObject = false; | ||
31 | size_t checkpointMapObjectIndex; | ||
32 | |||
30 | }; | 33 | }; |
31 | 34 | ||
32 | #endif /* end of include guard: PLAYABLE_H_DDC566C3 */ | 35 | #endif /* end of include guard: PLAYABLE_H_DDC566C3 */ |
diff --git a/src/components/ponderable.h b/src/components/ponderable.h index e6aa976..221d267 100644 --- a/src/components/ponderable.h +++ b/src/components/ponderable.h | |||
@@ -34,7 +34,8 @@ public: | |||
34 | platform, | 34 | platform, |
35 | adjacency, | 35 | adjacency, |
36 | warp, | 36 | warp, |
37 | danger | 37 | danger, |
38 | event | ||
38 | }; | 39 | }; |
39 | 40 | ||
40 | /** | 41 | /** |
diff --git a/src/components/prototypable.h b/src/components/prototypable.h new file mode 100644 index 0000000..4659e7c --- /dev/null +++ b/src/components/prototypable.h | |||
@@ -0,0 +1,22 @@ | |||
1 | #ifndef PROTOTYPABLE_H_817F2205 | ||
2 | #define PROTOTYPABLE_H_817F2205 | ||
3 | |||
4 | #include "component.h" | ||
5 | #include "entity_manager.h" | ||
6 | |||
7 | class PrototypableComponent : public Component { | ||
8 | public: | ||
9 | |||
10 | using id_type = EntityManager::id_type; | ||
11 | |||
12 | size_t mapObjectIndex; | ||
13 | |||
14 | std::string prototypeId; | ||
15 | |||
16 | bool hasBehavior = false; | ||
17 | bool runningBehavior = false; | ||
18 | |||
19 | id_type behaviorScript; | ||
20 | }; | ||
21 | |||
22 | #endif /* end of include guard: PROTOTYPABLE_H_817F2205 */ | ||
diff --git a/src/components/realizable.h b/src/components/realizable.h index bc834a2..b749aeb 100644 --- a/src/components/realizable.h +++ b/src/components/realizable.h | |||
@@ -4,7 +4,6 @@ | |||
4 | #include "component.h" | 4 | #include "component.h" |
5 | #include <set> | 5 | #include <set> |
6 | #include <map> | 6 | #include <map> |
7 | #include <sol.hpp> | ||
8 | #include "entity_manager.h" | 7 | #include "entity_manager.h" |
9 | #include "vector.h" | 8 | #include "vector.h" |
10 | 9 | ||
@@ -70,8 +69,6 @@ public: | |||
70 | * The entity ID of the currently active player. | 69 | * The entity ID of the currently active player. |
71 | */ | 70 | */ |
72 | id_type activePlayer; | 71 | id_type activePlayer; |
73 | |||
74 | sol::state scriptEngine; | ||
75 | }; | 72 | }; |
76 | 73 | ||
77 | #endif /* end of include guard: REALIZABLE_H_36D8D71E */ | 74 | #endif /* end of include guard: REALIZABLE_H_36D8D71E */ |
diff --git a/src/components/runnable.h b/src/components/runnable.h new file mode 100644 index 0000000..1b994fb --- /dev/null +++ b/src/components/runnable.h | |||
@@ -0,0 +1,15 @@ | |||
1 | #ifndef AUTOMATABLE_H_3D519131 | ||
2 | #define AUTOMATABLE_H_3D519131 | ||
3 | |||
4 | #include "component.h" | ||
5 | #include <sol.hpp> | ||
6 | #include <memory> | ||
7 | |||
8 | class RunnableComponent : public Component { | ||
9 | public: | ||
10 | |||
11 | std::unique_ptr<sol::thread> runner; | ||
12 | std::unique_ptr<sol::coroutine> callable; | ||
13 | }; | ||
14 | |||
15 | #endif /* end of include guard: AUTOMATABLE_H_3D519131 */ | ||
diff --git a/src/game.cpp b/src/game.cpp index bf2b10b..f2992e1 100644 --- a/src/game.cpp +++ b/src/game.cpp | |||
@@ -12,7 +12,7 @@ | |||
12 | #include "systems/playing.h" | 12 | #include "systems/playing.h" |
13 | #include "systems/scheduling.h" | 13 | #include "systems/scheduling.h" |
14 | #include "systems/realizing.h" | 14 | #include "systems/realizing.h" |
15 | #include "systems/automating.h" | 15 | #include "systems/scripting.h" |
16 | #include "animation.h" | 16 | #include "animation.h" |
17 | #include "consts.h" | 17 | #include "consts.h" |
18 | 18 | ||
@@ -36,7 +36,7 @@ Game::Game(std::mt19937& rng) : rng_(rng) | |||
36 | systemManager_.emplaceSystem<PlayingSystem>(*this); | 36 | systemManager_.emplaceSystem<PlayingSystem>(*this); |
37 | systemManager_.emplaceSystem<SchedulingSystem>(*this); | 37 | systemManager_.emplaceSystem<SchedulingSystem>(*this); |
38 | systemManager_.emplaceSystem<ControllingSystem>(*this); | 38 | systemManager_.emplaceSystem<ControllingSystem>(*this); |
39 | systemManager_.emplaceSystem<AutomatingSystem>(*this); | 39 | systemManager_.emplaceSystem<ScriptingSystem>(*this); |
40 | systemManager_.emplaceSystem<OrientingSystem>(*this); | 40 | systemManager_.emplaceSystem<OrientingSystem>(*this); |
41 | systemManager_.emplaceSystem<PonderingSystem>(*this); | 41 | systemManager_.emplaceSystem<PonderingSystem>(*this); |
42 | systemManager_.emplaceSystem<MappingSystem>(*this); | 42 | systemManager_.emplaceSystem<MappingSystem>(*this); |
diff --git a/src/systems/automating.cpp b/src/systems/automating.cpp deleted file mode 100644 index 4a5357d..0000000 --- a/src/systems/automating.cpp +++ /dev/null | |||
@@ -1,106 +0,0 @@ | |||
1 | #include "automating.h" | ||
2 | #include "game.h" | ||
3 | #include "components/automatable.h" | ||
4 | #include "components/ponderable.h" | ||
5 | #include "components/realizable.h" | ||
6 | #include "components/transformable.h" | ||
7 | #include "systems/realizing.h" | ||
8 | #include "vector.h" | ||
9 | |||
10 | struct script_entity { | ||
11 | using id_type = EntityManager::id_type; | ||
12 | |||
13 | id_type id; | ||
14 | |||
15 | script_entity(id_type id) : id(id) | ||
16 | { | ||
17 | } | ||
18 | }; | ||
19 | |||
20 | void AutomatingSystem::tick(double dt) | ||
21 | { | ||
22 | auto entities = game_.getEntityManager().getEntitiesWithComponents< | ||
23 | AutomatableComponent>(); | ||
24 | |||
25 | for (id_type entity : entities) | ||
26 | { | ||
27 | auto& automatable = game_.getEntityManager(). | ||
28 | getComponent<AutomatableComponent>(entity); | ||
29 | |||
30 | if (!automatable.active) | ||
31 | { | ||
32 | continue; | ||
33 | } | ||
34 | |||
35 | auto result = (*automatable.behavior)(dt); | ||
36 | if (!result.valid()) | ||
37 | { | ||
38 | sol::error e = result; | ||
39 | throw std::runtime_error(e.what()); | ||
40 | } | ||
41 | } | ||
42 | } | ||
43 | |||
44 | void AutomatingSystem::initPrototype(id_type prototype) | ||
45 | { | ||
46 | auto& automatable = game_.getEntityManager(). | ||
47 | getComponent<AutomatableComponent>(prototype); | ||
48 | |||
49 | auto& realizable = game_.getEntityManager(). | ||
50 | getComponent<RealizableComponent>( | ||
51 | game_.getSystemManager().getSystem<RealizingSystem>().getSingleton()); | ||
52 | automatable.behavior.reset(); | ||
53 | automatable.runner = std::unique_ptr<sol::thread>(new sol::thread(sol::thread::create(realizable.scriptEngine.lua_state()))); | ||
54 | automatable.behavior = std::unique_ptr<sol::coroutine>(new sol::coroutine(automatable.runner->state()["run"])); | ||
55 | |||
56 | auto result = (*automatable.behavior)(script_entity(prototype)); | ||
57 | if (!result.valid()) | ||
58 | { | ||
59 | sol::error e = result; | ||
60 | throw std::runtime_error(e.what()); | ||
61 | } | ||
62 | } | ||
63 | |||
64 | void AutomatingSystem::initScriptEngine(sol::state& scriptEngine) | ||
65 | { | ||
66 | scriptEngine.open_libraries(sol::lib::base, sol::lib::coroutine); | ||
67 | scriptEngine.new_usertype<vec2d>( | ||
68 | "vec2d", | ||
69 | sol::constructors<vec2d(), vec2d(double, double)>(), | ||
70 | "x", sol::property( | ||
71 | [] (vec2d& v) -> double { return v.x(); }, | ||
72 | [] (vec2d& v, double x) { v.x() = x; }), | ||
73 | "y", sol::property( | ||
74 | [] (vec2d& v) -> double { return v.y(); }, | ||
75 | [] (vec2d& v, double y) { v.y() = y; })); | ||
76 | |||
77 | scriptEngine.new_usertype<vec2i>( | ||
78 | "vec2i", | ||
79 | sol::constructors<vec2i(), vec2i(int, int)>(), | ||
80 | "x", [] (vec2i& v) -> int& { return v.x(); }, | ||
81 | "y", [] (vec2i& v) -> int& { return v.y(); }); | ||
82 | |||
83 | scriptEngine.new_usertype<script_entity>( | ||
84 | "entity", | ||
85 | sol::constructors<script_entity(id_type)>(), | ||
86 | "id", &script_entity::id, | ||
87 | "transformable", | ||
88 | [&] (script_entity& entity) -> TransformableComponent& { | ||
89 | return game_.getEntityManager(). | ||
90 | getComponent<TransformableComponent>(entity.id); | ||
91 | }, | ||
92 | "ponderable", | ||
93 | [&] (script_entity& entity) -> PonderableComponent& { | ||
94 | return game_.getEntityManager(). | ||
95 | getComponent<PonderableComponent>(entity.id); | ||
96 | }); | ||
97 | |||
98 | scriptEngine.new_usertype<TransformableComponent>( | ||
99 | "transformable", | ||
100 | "pos", &TransformableComponent::pos); | ||
101 | |||
102 | scriptEngine.new_usertype<PonderableComponent>( | ||
103 | "ponderable", | ||
104 | "vel", &PonderableComponent::vel, | ||
105 | "accel", &PonderableComponent::accel); | ||
106 | } | ||
diff --git a/src/systems/automating.h b/src/systems/automating.h deleted file mode 100644 index 117b622..0000000 --- a/src/systems/automating.h +++ /dev/null | |||
@@ -1,22 +0,0 @@ | |||
1 | #ifndef AUTOMATING_H_E6E5D76E | ||
2 | #define AUTOMATING_H_E6E5D76E | ||
3 | |||
4 | #include "system.h" | ||
5 | #include <sol.hpp> | ||
6 | |||
7 | class AutomatingSystem : public System { | ||
8 | public: | ||
9 | |||
10 | AutomatingSystem(Game& game) : System(game) | ||
11 | { | ||
12 | } | ||
13 | |||
14 | void tick(double dt); | ||
15 | |||
16 | void initPrototype(id_type prototype); | ||
17 | |||
18 | void initScriptEngine(sol::state& scriptEngine); | ||
19 | |||
20 | }; | ||
21 | |||
22 | #endif /* end of include guard: AUTOMATING_H_E6E5D76E */ | ||
diff --git a/src/systems/pondering.cpp b/src/systems/pondering.cpp index c806cc8..a3eb36d 100644 --- a/src/systems/pondering.cpp +++ b/src/systems/pondering.cpp | |||
@@ -11,6 +11,7 @@ | |||
11 | #include "systems/orienting.h" | 11 | #include "systems/orienting.h" |
12 | #include "systems/playing.h" | 12 | #include "systems/playing.h" |
13 | #include "systems/realizing.h" | 13 | #include "systems/realizing.h" |
14 | #include "systems/scripting.h" | ||
14 | #include "consts.h" | 15 | #include "consts.h" |
15 | 16 | ||
16 | void PonderingSystem::tick(double dt) | 17 | void PonderingSystem::tick(double dt) |
@@ -857,6 +858,18 @@ void PonderingSystem::processCollision( | |||
857 | break; | 858 | break; |
858 | } | 859 | } |
859 | 860 | ||
861 | case PonderableComponent::Collision::event: | ||
862 | { | ||
863 | if (game_.getEntityManager(). | ||
864 | hasComponent<PlayableComponent>(entity)) | ||
865 | { | ||
866 | game_.getSystemManager().getSystem<ScriptingSystem>(). | ||
867 | onTouch(collider, entity); | ||
868 | } | ||
869 | |||
870 | break; | ||
871 | } | ||
872 | |||
860 | default: | 873 | default: |
861 | { | 874 | { |
862 | // Not yet implemented. | 875 | // Not yet implemented. |
diff --git a/src/systems/realizing.cpp b/src/systems/realizing.cpp index 28e2279..2ee5897 100644 --- a/src/systems/realizing.cpp +++ b/src/systems/realizing.cpp | |||
@@ -12,11 +12,11 @@ | |||
12 | #include "components/playable.h" | 12 | #include "components/playable.h" |
13 | #include "components/ponderable.h" | 13 | #include "components/ponderable.h" |
14 | #include "components/transformable.h" | 14 | #include "components/transformable.h" |
15 | #include "components/automatable.h" | 15 | #include "components/prototypable.h" |
16 | #include "systems/mapping.h" | 16 | #include "systems/mapping.h" |
17 | #include "systems/animating.h" | 17 | #include "systems/animating.h" |
18 | #include "systems/pondering.h" | 18 | #include "systems/pondering.h" |
19 | #include "systems/automating.h" | 19 | #include "systems/scripting.h" |
20 | 20 | ||
21 | inline xmlChar* getProp(xmlNodePtr node, const char* attr) | 21 | inline xmlChar* getProp(xmlNodePtr node, const char* attr) |
22 | { | 22 | { |
@@ -40,9 +40,6 @@ EntityManager::id_type RealizingSystem::initSingleton( | |||
40 | auto& realizable = game_.getEntityManager(). | 40 | auto& realizable = game_.getEntityManager(). |
41 | emplaceComponent<RealizableComponent>(world); | 41 | emplaceComponent<RealizableComponent>(world); |
42 | 42 | ||
43 | game_.getSystemManager().getSystem<AutomatingSystem>(). | ||
44 | initScriptEngine(realizable.scriptEngine); | ||
45 | |||
46 | realizable.worldFile = worldFile; | 43 | realizable.worldFile = worldFile; |
47 | realizable.prototypeFile = prototypeFile; | 44 | realizable.prototypeFile = prototypeFile; |
48 | 45 | ||
@@ -216,14 +213,28 @@ EntityManager::id_type RealizingSystem::initSingleton( | |||
216 | game_.getSystemManager().getSystem<PonderingSystem>(). | 213 | game_.getSystemManager().getSystem<PonderingSystem>(). |
217 | initializeBody(mapObject, PonderableComponent::Type::vacuumed); | 214 | initializeBody(mapObject, PonderableComponent::Type::vacuumed); |
218 | 215 | ||
216 | |||
217 | |||
218 | |||
219 | |||
220 | auto& prototypable = game_.getEntityManager(). | ||
221 | emplaceComponent<PrototypableComponent>(mapObject); | ||
222 | |||
223 | prototypable.prototypeId = prototypeId; | ||
224 | |||
225 | key = getProp(mapNode, "index"); | ||
226 | prototypable.mapObjectIndex = atoi(reinterpret_cast<char*>(key)); | ||
227 | xmlFree(key); | ||
228 | |||
219 | if (prototypeId == "movplat") | 229 | if (prototypeId == "movplat") |
220 | { | 230 | { |
221 | auto& automatable = game_.getEntityManager(). | 231 | prototypable.hasBehavior = true; |
222 | emplaceComponent<AutomatableComponent>(mapObject); | 232 | } else if (prototypeId == "checkpoint") |
223 | 233 | { | |
234 | auto& ponderable = game_.getEntityManager(). | ||
235 | getComponent<PonderableComponent>(mapObject); | ||
224 | 236 | ||
225 | realizable.scriptEngine.script_file( | 237 | ponderable.colliderType = PonderableComponent::Collision::event; |
226 | "res/platform.lua");//, | ||
227 | } | 238 | } |
228 | 239 | ||
229 | mappable.objects.push_back(mapObject); | 240 | mappable.objects.push_back(mapObject); |
@@ -319,7 +330,6 @@ void RealizingSystem::loadMap(id_type mapEntity) | |||
319 | 330 | ||
320 | auto& animating = game_.getSystemManager().getSystem<AnimatingSystem>(); | 331 | auto& animating = game_.getSystemManager().getSystem<AnimatingSystem>(); |
321 | auto& pondering = game_.getSystemManager().getSystem<PonderingSystem>(); | 332 | auto& pondering = game_.getSystemManager().getSystem<PonderingSystem>(); |
322 | auto& automating = game_.getSystemManager().getSystem<AutomatingSystem>(); | ||
323 | 333 | ||
324 | std::set<id_type> players = | 334 | std::set<id_type> players = |
325 | game_.getEntityManager().getEntitiesWithComponents< | 335 | game_.getEntityManager().getEntitiesWithComponents< |
@@ -380,11 +390,6 @@ void RealizingSystem::loadMap(id_type mapEntity) | |||
380 | pondering.initPrototype(prototype); | 390 | pondering.initPrototype(prototype); |
381 | } | 391 | } |
382 | 392 | ||
383 | if (game_.getEntityManager().hasComponent<AutomatableComponent>(prototype)) | ||
384 | { | ||
385 | automating.initPrototype(prototype); | ||
386 | } | ||
387 | |||
388 | enterActiveMap(prototype); | 393 | enterActiveMap(prototype); |
389 | } | 394 | } |
390 | 395 | ||
@@ -419,12 +424,19 @@ void RealizingSystem::enterActiveMap(id_type entity) | |||
419 | ponderable.active = true; | 424 | ponderable.active = true; |
420 | } | 425 | } |
421 | 426 | ||
422 | if (game_.getEntityManager().hasComponent<AutomatableComponent>(entity)) | 427 | if (game_.getEntityManager().hasComponent<PrototypableComponent>(entity)) |
423 | { | 428 | { |
424 | auto& automatable = game_.getEntityManager(). | 429 | auto& prototypable = game_.getEntityManager(). |
425 | getComponent<AutomatableComponent>(entity); | 430 | getComponent<PrototypableComponent>(entity); |
431 | |||
432 | if (prototypable.hasBehavior) | ||
433 | { | ||
434 | auto& scripting = game_.getSystemManager().getSystem<ScriptingSystem>(); | ||
426 | 435 | ||
427 | automatable.active = true; | 436 | prototypable.hasBehavior = true; |
437 | prototypable.runningBehavior = true; | ||
438 | prototypable.behaviorScript = scripting.runBehaviorScript(entity); | ||
439 | } | ||
428 | } | 440 | } |
429 | } | 441 | } |
430 | 442 | ||
@@ -446,11 +458,17 @@ void RealizingSystem::leaveActiveMap(id_type entity) | |||
446 | ponderable.active = false; | 458 | ponderable.active = false; |
447 | } | 459 | } |
448 | 460 | ||
449 | if (game_.getEntityManager().hasComponent<AutomatableComponent>(entity)) | 461 | if (game_.getEntityManager().hasComponent<PrototypableComponent>(entity)) |
450 | { | 462 | { |
451 | auto& automatable = game_.getEntityManager(). | 463 | auto& prototypable = game_.getEntityManager(). |
452 | getComponent<AutomatableComponent>(entity); | 464 | getComponent<PrototypableComponent>(entity); |
453 | 465 | ||
454 | automatable.active = false; | 466 | if (prototypable.runningBehavior) |
467 | { | ||
468 | auto& scripting = game_.getSystemManager().getSystem<ScriptingSystem>(); | ||
469 | scripting.killScript(prototypable.behaviorScript); | ||
470 | |||
471 | prototypable.runningBehavior = false; | ||
472 | } | ||
455 | } | 473 | } |
456 | } | 474 | } |
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 | |||
13 | struct 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 | |||
23 | ScriptingSystem::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 | |||
127 | void 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 | |||
154 | void ScriptingSystem::killScript(id_type entity) | ||
155 | { | ||
156 | if (game_.getEntityManager().hasComponent<RunnableComponent>(entity)) | ||
157 | { | ||
158 | game_.getEntityManager().deleteEntity(entity); | ||
159 | } | ||
160 | } | ||
161 | |||
162 | template <typename... Args> | ||
163 | EntityManager::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 | |||
208 | EntityManager::id_type ScriptingSystem::runBehaviorScript(id_type entity) | ||
209 | { | ||
210 | return runScript("Behavior", entity); | ||
211 | } | ||
212 | |||
213 | void ScriptingSystem::onTouch(id_type entity, id_type player) | ||
214 | { | ||
215 | runScript( | ||
216 | "OnTouch", | ||
217 | entity, | ||
218 | script_entity(player)); | ||
219 | } | ||
diff --git a/src/systems/scripting.h b/src/systems/scripting.h new file mode 100644 index 0000000..d5380f1 --- /dev/null +++ b/src/systems/scripting.h | |||
@@ -0,0 +1,28 @@ | |||
1 | #ifndef AUTOMATING_H_E6E5D76E | ||
2 | #define AUTOMATING_H_E6E5D76E | ||
3 | |||
4 | #include "system.h" | ||
5 | #include <sol.hpp> | ||
6 | |||
7 | class ScriptingSystem : public System { | ||
8 | public: | ||
9 | |||
10 | ScriptingSystem(Game& game); | ||
11 | |||
12 | void tick(double dt); | ||
13 | |||
14 | void killScript(id_type entity); | ||
15 | |||
16 | id_type runBehaviorScript(id_type entity); | ||
17 | |||
18 | void onTouch(id_type entity, id_type player); | ||
19 | |||
20 | private: | ||
21 | |||
22 | template <typename... Args> | ||
23 | id_type runScript(std::string event, id_type entity, Args&&... args); | ||
24 | |||
25 | sol::state engine; | ||
26 | }; | ||
27 | |||
28 | #endif /* end of include guard: AUTOMATING_H_E6E5D76E */ | ||