diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/components/automatable.h | 34 | ||||
| -rw-r--r-- | src/components/prototypable.h | 11 | ||||
| -rw-r--r-- | src/components/runnable.h | 36 | ||||
| -rw-r--r-- | src/game.h | 2 | ||||
| -rw-r--r-- | src/systems/realizing.cpp | 33 | ||||
| -rw-r--r-- | src/systems/scripting.cpp | 70 | ||||
| -rw-r--r-- | src/systems/scripting.h | 10 |
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 | |||
| 7 | class AutomatableComponent : public Component { | ||
| 8 | public: | ||
| 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 | ||
| 8 | class RunnableComponent : public Component { | 9 | class RunnableComponent : public Component { |
| 9 | public: | 10 | public: |
| 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 | ||
| 141 | void ScriptingSystem::killScript(id_type entity) | 142 | void 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 | ||
| 149 | template <typename... Args> | 158 | template <typename... Args> |
| 150 | EntityManager::id_type ScriptingSystem::runScript( | 159 | sol::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 | |||
| 209 | void 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 | ||
| 195 | EntityManager::id_type ScriptingSystem::runBehaviorScript(id_type entity) | 233 | void 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 | ||
| 200 | void ScriptingSystem::onTouch(id_type entity, id_type player) | 244 | void 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 | ||
| 20 | private: | 22 | private: |
| 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 | }; |
