From e01b3d63467dac6918b034c84ce91b830bef0feb Mon Sep 17 00:00:00 2001
From: Dominic Masters <dominic@domsplace.com>
Date: Mon, 24 Apr 2023 20:04:31 -0700
Subject: [PATCH] Parallel event processing

---
 src/dawnliminal/game/LiminalGame.cpp          |   4 +-
 src/dawntools/vnscenetool/CMakeLists.txt      |   1 -
 src/dawntools/vnscenetool/VNSceneGen.cpp      | 130 +++++++++++-------
 src/dawntools/vnscenetool/VNSceneGen.hpp      |   8 ++
 src/dawntools/vnscenetool/VNSceneParser.hpp   |   2 +-
 .../vnscenetool/events/CMakeLists.txt         |   3 +
 .../events/VNParallelEventParser.cpp          |  27 ++++
 .../events/VNParallelEventParser.hpp          |  23 ++++
 .../{ => events}/VNSceneEventsParser.cpp      |  13 +-
 .../{ => events}/VNSceneEventsParser.hpp      |  28 ++--
 .../vnscenetool/events/VNWaitEventParser.cpp  |  35 +++++
 .../vnscenetool/events/VNWaitEventParser.hpp  |  25 ++++
 12 files changed, 238 insertions(+), 61 deletions(-)
 create mode 100644 src/dawntools/vnscenetool/events/VNParallelEventParser.cpp
 create mode 100644 src/dawntools/vnscenetool/events/VNParallelEventParser.hpp
 rename src/dawntools/vnscenetool/{ => events}/VNSceneEventsParser.cpp (77%)
 rename src/dawntools/vnscenetool/{ => events}/VNSceneEventsParser.hpp (68%)
 create mode 100644 src/dawntools/vnscenetool/events/VNWaitEventParser.cpp
 create mode 100644 src/dawntools/vnscenetool/events/VNWaitEventParser.hpp

diff --git a/src/dawnliminal/game/LiminalGame.cpp b/src/dawnliminal/game/LiminalGame.cpp
index 4c28a4cb..7bec3cab 100644
--- a/src/dawnliminal/game/LiminalGame.cpp
+++ b/src/dawnliminal/game/LiminalGame.cpp
@@ -10,6 +10,6 @@
 using namespace Dawn;
 
 Scene * Dawn::dawnGameGetInitialScene(DawnGame *game) {
-  return new HelloWorldScene(game);
-  // return new TestScene(game);
+  // return new HelloWorldScene(game);
+  return new TestScene(game);
 }
\ No newline at end of file
diff --git a/src/dawntools/vnscenetool/CMakeLists.txt b/src/dawntools/vnscenetool/CMakeLists.txt
index 865f7454..028c7b4b 100644
--- a/src/dawntools/vnscenetool/CMakeLists.txt
+++ b/src/dawntools/vnscenetool/CMakeLists.txt
@@ -17,7 +17,6 @@ target_sources(vnscenetool
     ${DAWN_TOOL_SOURCES}
     VNSceneTool.cpp
     VNSceneParser.cpp
-    VNSceneEventsParser.cpp
     VNSceneGen.cpp
     VNSceneItemParser.cpp
 )
diff --git a/src/dawntools/vnscenetool/VNSceneGen.cpp b/src/dawntools/vnscenetool/VNSceneGen.cpp
index 7b439e7f..cfa55f0e 100644
--- a/src/dawntools/vnscenetool/VNSceneGen.cpp
+++ b/src/dawntools/vnscenetool/VNSceneGen.cpp
@@ -7,6 +7,81 @@
 
 using namespace Dawn;
 
+void VNSceneGen::test(
+  std::string eventName,
+  struct VNSceneEvent *event,
+  int32_t *eventIndex,
+  std::vector<std::string> *body,
+  std::vector<std::string> *includes
+) {
+  std::string initType = "";
+  std::string toInclude = "";
+  std::string initArgs = "";
+  std::vector<std::string> afterLines;
+
+  switch(event->type) {
+    case VN_SCENE_EVENT_TYPE_TEXT:
+      initType = "VNTextEvent";
+      toInclude = "games/vn/events/VNTextEvent.hpp";
+      line(body, eventName + "->" + "text = \"" + event->text.texts.begin()->text + "\";", "");
+      break;
+
+    case VN_SCENE_EVENT_TYPE_POSITION:
+      initType = "VNPositionEvent";
+      toInclude = "games/vn/events/VNPositionEvent.hpp";
+      line(&afterLines, eventName + "->item = " + event->position.item + ";", "");
+      if(event->position.x != "") line(&afterLines, eventName + "->" + "to.x = " + event->position.x + ";", "");
+      if(event->position.y != "") line(&afterLines, eventName + "->" + "to.y = " + event->position.y + ";", "");
+      if(event->position.z != "") line(&afterLines, eventName + "->" + "to.z = " + event->position.z + ";", "");
+      break;
+
+    case VN_SCENE_EVENT_TYPE_SET:
+      initType = "VNSetEvent<" + event->set.type + ">";
+      toInclude = "games/vn/events/VNSetEvent.hpp";
+      line(&afterLines, eventName + "->modifies = &" + event->set.property + ";", "");
+      line(&afterLines, eventName + "->to = " + event->set.to + ";", "");
+      if(event->set.from != "") line(&afterLines, eventName + "->from = " + event->set.from + ";", "");
+      if(event->set.duration != "") line(&afterLines, eventName + "->duration = " + event->set.duration + ";", "");
+      break;
+
+    case VN_SCENE_EVENT_TYPE_WAIT:
+      initType = "VNWaitEvent";
+      toInclude = "games/vn/events/VNWaitEvent.hpp";
+      line(&afterLines, eventName + "->duration = " + event->wait.duration + ";", "");
+      break;
+
+    case VN_SCENE_EVENT_TYPE_PARALLEL: {
+      initType = "VNParallelEvent";
+      toInclude = "games/vn/events/VNParallelEvent.hpp";
+
+      auto itParallel = event->parallel.events.events.begin();
+      while(itParallel != event->parallel.events.events.end()) {
+        std::string pEventName = "pEvent" + std::to_string((*eventIndex)++);
+        VNSceneGen::test(
+          pEventName,
+          &(*itParallel),
+          eventIndex,
+          &afterLines,
+          includes
+        );
+        line(&afterLines, eventName + "->events.push_back(" + pEventName + ");", "");
+        line(&afterLines, "", "");
+        ++itParallel;
+      }
+      break;
+    }
+
+    default:
+      std::cout << "Unknown event type: " << event->type << std::endl;
+      assertUnreachable();
+  }
+
+  if(!toInclude.empty()) includes->push_back(toInclude);
+
+  line(body, "auto " + eventName + " = vnManager->createEvent<" + initType + ">(" + initArgs + ");", "");
+  lines(body, afterLines, "");
+}
+
 void VNSceneGen::generate(
   std::vector<std::string> *out,
   struct VNScene *scene,
@@ -67,56 +142,19 @@ void VNSceneGen::generate(
 
   int32_t eventIndex = 0;
   auto itEvents = scene->events.events.begin();
+  std::string previous = "eventStart";
   while(itEvents != scene->events.events.end()) {
-    std::string eventName = "event" + std::to_string(eventIndex);
-    std::string initType = "";
-    std::string initArgs = "";
-    std::string toInclude = "";
-    std::string prev = "previous";
-    std::vector<std::string> afterLines;
-
-    switch(itEvents->type) {
-      case VN_SCENE_EVENT_TYPE_TEXT:
-        initType = "VNTextEvent";
-        toInclude = "games/vn/events/VNTextEvent.hpp";
-        line(&afterLines, eventName + "->" + "text = \"" + itEvents->text.texts.begin()->text + "\";", "");
-        break;
-
-      case VN_SCENE_EVENT_TYPE_POSITION:
-        initType = "VNPositionEvent";
-        toInclude = "games/vn/events/VNPositionEvent.hpp";
-        line(&afterLines, eventName + "->item = " + itEvents->position.item + ";", "");
-        if(itEvents->position.x != "") line(&afterLines, eventName + "->" + "to.x = " + itEvents->position.x + ";", "");
-        if(itEvents->position.y != "") line(&afterLines, eventName + "->" + "to.y = " + itEvents->position.y + ";", "");
-        if(itEvents->position.z != "") line(&afterLines, eventName + "->" + "to.z = " + itEvents->position.z + ";", "");
-        break;
-
-      case VN_SCENE_EVENT_TYPE_SET:
-        initType = "VNSetEvent<" + itEvents->set.type + ">";
-        toInclude = "games/vn/events/VNSetEvent.hpp";
-        line(&afterLines, eventName + "->modifies = &" + itEvents->set.property + ";", "");
-        line(&afterLines, eventName + "->to = " + itEvents->set.to + ";", "");
-        if(itEvents->set.from != "") line(&afterLines, eventName + "->from = " + itEvents->set.from + ";", "");
-        if(itEvents->set.duration != "") line(&afterLines, eventName + "->duration = " + itEvents->set.duration + ";", "");
-        break;
-
-
-      default:
-        std::cout << "Unknown event type: " << itEvents->type << std::endl;
-        assertUnreachable();
-    }
-
-    if(!toInclude.empty()) classInfo.includes.push_back(toInclude);
     line(&methodStage.body, "", "");
-    line(
+    std::string eventName = "event" + std::to_string(eventIndex++);
+    VNSceneGen::test(
+      eventName,
+      &(*itEvents),
+      &eventIndex,
       &methodStage.body,
-      "auto " + eventName + " = " + prev + "->then(vnManager->createEvent<" + initType + ">(" + initArgs + "));",
-      ""
+      &classInfo.includes
     );
-    line(&methodStage.body, "previous = " + eventName + ";", "");
-    lines(&methodStage.body, afterLines, "");
-    
-    eventIndex++;
+    line(&methodStage.body, previous + "->then(" + eventName + ");", "");
+    previous = eventName;
     ++itEvents;
   }
 
diff --git a/src/dawntools/vnscenetool/VNSceneGen.hpp b/src/dawntools/vnscenetool/VNSceneGen.hpp
index 8a704b89..c70c9aed 100644
--- a/src/dawntools/vnscenetool/VNSceneGen.hpp
+++ b/src/dawntools/vnscenetool/VNSceneGen.hpp
@@ -10,6 +10,14 @@
 namespace Dawn {
   class VNSceneGen : public CodeGen {
     public:
+      static void test(
+        std::string eventName,
+        struct VNSceneEvent *event,
+        int32_t *eventIndex,
+        std::vector<std::string> *body,
+        std::vector<std::string> *includes
+      );
+
       static void generate(
         std::vector<std::string> *out,
         struct VNScene *scene,
diff --git a/src/dawntools/vnscenetool/VNSceneParser.hpp b/src/dawntools/vnscenetool/VNSceneParser.hpp
index 8a391919..17f661c4 100644
--- a/src/dawntools/vnscenetool/VNSceneParser.hpp
+++ b/src/dawntools/vnscenetool/VNSceneParser.hpp
@@ -5,7 +5,7 @@
 
 #pragma once
 #include "VNSceneItemParser.hpp"
-#include "VNSceneEventsParser.hpp"
+#include "events/VNSceneEventsParser.hpp"
 
 namespace Dawn {
   struct VNScene {
diff --git a/src/dawntools/vnscenetool/events/CMakeLists.txt b/src/dawntools/vnscenetool/events/CMakeLists.txt
index 31ac61e8..9703f802 100644
--- a/src/dawntools/vnscenetool/events/CMakeLists.txt
+++ b/src/dawntools/vnscenetool/events/CMakeLists.txt
@@ -6,7 +6,10 @@
 # Sources
 target_sources(vnscenetool
   PRIVATE
+    VNSceneEventsParser.cpp
     VNPositionEventParser.cpp
     VNTextEventParser.cpp
     VNSetEventParser.cpp
+    VNWaitEventParser.cpp
+    VNParallelEventParser.cpp
 )
\ No newline at end of file
diff --git a/src/dawntools/vnscenetool/events/VNParallelEventParser.cpp b/src/dawntools/vnscenetool/events/VNParallelEventParser.cpp
new file mode 100644
index 00000000..a811bc65
--- /dev/null
+++ b/src/dawntools/vnscenetool/events/VNParallelEventParser.cpp
@@ -0,0 +1,27 @@
+// Copyright (c) 2023 Dominic Masters
+// 
+// This software is released under the MIT License.
+// https://opensource.org/licenses/MIT
+
+#include "VNParallelEventParser.hpp"
+#include "VNSceneEventsParser.hpp"
+
+using namespace Dawn;
+
+std::vector<std::string> VNParallelEventParser::getRequiredAttributes() {
+  return std::vector<std::string>();
+}
+
+std::map<std::string, std::string> VNParallelEventParser::getOptionalAttributes() {
+  return std::map<std::string, std::string>();
+}
+
+int32_t VNParallelEventParser::onParse(
+  Xml *node,
+  std::map<std::string, std::string> values,
+  struct VNParallelEvent *out,
+  std::string *error
+) {
+  // Parse all children
+  return (VNSceneEventsParser()).parse(node, &out->events, error);
+}
\ No newline at end of file
diff --git a/src/dawntools/vnscenetool/events/VNParallelEventParser.hpp b/src/dawntools/vnscenetool/events/VNParallelEventParser.hpp
new file mode 100644
index 00000000..07169f91
--- /dev/null
+++ b/src/dawntools/vnscenetool/events/VNParallelEventParser.hpp
@@ -0,0 +1,23 @@
+// Copyright (c) 2023 Dominic Masters
+// 
+// This software is released under the MIT License.
+// https://opensource.org/licenses/MIT
+
+#pragma once
+#include "util/XmlParser.hpp"
+
+namespace Dawn {
+  struct VNParallelEvent;
+
+  class VNParallelEventParser : public XmlParser<struct VNParallelEvent> {
+    protected:
+      std::vector<std::string> getRequiredAttributes() override;
+      std::map<std::string, std::string> getOptionalAttributes() override;
+      int32_t onParse(
+        Xml *node,
+        std::map<std::string, std::string> values,
+        struct VNParallelEvent *out,
+        std::string *error
+      ) override;
+  };
+}
\ No newline at end of file
diff --git a/src/dawntools/vnscenetool/VNSceneEventsParser.cpp b/src/dawntools/vnscenetool/events/VNSceneEventsParser.cpp
similarity index 77%
rename from src/dawntools/vnscenetool/VNSceneEventsParser.cpp
rename to src/dawntools/vnscenetool/events/VNSceneEventsParser.cpp
index fe8223e7..e4c6ab34 100644
--- a/src/dawntools/vnscenetool/VNSceneEventsParser.cpp
+++ b/src/dawntools/vnscenetool/events/VNSceneEventsParser.cpp
@@ -4,6 +4,7 @@
 // https://opensource.org/licenses/MIT
 
 #include "VNSceneEventsParser.hpp"
+#include "VNParallelEventParser.hpp"
 
 using namespace Dawn;
 
@@ -30,23 +31,29 @@ int32_t VNSceneEventsParser::onParse(
 
     // Parse event(s)
     if(child->node == "text") {
-      VNTextEventParser parser;
       event.type = VN_SCENE_EVENT_TYPE_TEXT;
       ret = (VNTextEventParser()).parse(child, &event.text, error);
       if(ret != 0) return ret;
     
     } else if(child->node == "position") {
-      VNPositionEventParser parser;
       event.type = VN_SCENE_EVENT_TYPE_POSITION;
       ret = (VNPositionEventParser()).parse(child, &event.position, error);
       if(ret != 0) return ret;
 
     } else if(child->node == "set") {
-      VNSetEvent parser;
       event.type = VN_SCENE_EVENT_TYPE_SET;
       ret = (VNSetEventParser()).parse(child, &event.set, error);
       if(ret != 0) return ret;
 
+    } else if(child->node == "wait") {
+      event.type = VN_SCENE_EVENT_TYPE_WAIT;
+      ret = (VNWaitEventParser()).parse(child, &event.wait, error);
+      if(ret != 0) return ret;
+
+    } else if(child->node == "parallel") {
+      event.type = VN_SCENE_EVENT_TYPE_PARALLEL;
+      ret = (VNParallelEventParser()).parse(child, &event.parallel, error);
+      if(ret != 0) return ret;
 
     } else {
       *error = "Unknown child node '" + child->node + "'";
diff --git a/src/dawntools/vnscenetool/VNSceneEventsParser.hpp b/src/dawntools/vnscenetool/events/VNSceneEventsParser.hpp
similarity index 68%
rename from src/dawntools/vnscenetool/VNSceneEventsParser.hpp
rename to src/dawntools/vnscenetool/events/VNSceneEventsParser.hpp
index 33849d9d..77f83642 100644
--- a/src/dawntools/vnscenetool/VNSceneEventsParser.hpp
+++ b/src/dawntools/vnscenetool/events/VNSceneEventsParser.hpp
@@ -4,15 +4,29 @@
 // https://opensource.org/licenses/MIT
 
 #pragma once
-#include "events/VNTextEventParser.hpp"
-#include "events/VNPositionEventParser.hpp"
-#include "events/VNSetEventParser.hpp"
+#include "VNTextEventParser.hpp"
+#include "VNPositionEventParser.hpp"
+#include "VNSetEventParser.hpp"
+#include "VNWaitEventParser.hpp"
+#include "VNParallelEventParser.hpp"
 
 namespace Dawn {
+  struct VNSceneEvent;
+
+  struct VNSceneEventList {
+    std::vector<struct VNSceneEvent> events;
+  };
+
   enum VNSceneEventType {
     VN_SCENE_EVENT_TYPE_TEXT,
     VN_SCENE_EVENT_TYPE_POSITION,
-    VN_SCENE_EVENT_TYPE_SET
+    VN_SCENE_EVENT_TYPE_SET,
+    VN_SCENE_EVENT_TYPE_WAIT,
+    VN_SCENE_EVENT_TYPE_PARALLEL
+  };
+
+  struct VNParallelEvent {
+    struct VNSceneEventList events;
   };
 
   struct VNSceneEvent {
@@ -21,10 +35,8 @@ namespace Dawn {
     struct VNTextEvent text;
     struct VNPositionEvent position;
     struct VNSetEvent set;
-  };
-
-  struct VNSceneEventList {
-    std::vector<struct VNSceneEvent> events;
+    struct VNWaitEvent wait;
+    struct VNParallelEvent parallel;
   };
 
   class VNSceneEventsParser : public XmlParser<struct VNSceneEventList> {
diff --git a/src/dawntools/vnscenetool/events/VNWaitEventParser.cpp b/src/dawntools/vnscenetool/events/VNWaitEventParser.cpp
new file mode 100644
index 00000000..f4cf8f65
--- /dev/null
+++ b/src/dawntools/vnscenetool/events/VNWaitEventParser.cpp
@@ -0,0 +1,35 @@
+// Copyright (c) 2023 Dominic Masters
+// 
+// This software is released under the MIT License.
+// https://opensource.org/licenses/MIT
+
+#include "VNWaitEventParser.hpp"
+
+using namespace Dawn;
+
+std::vector<std::string> VNWaitEventParser::getRequiredAttributes() {
+  return { };
+}
+
+std::map<std::string, std::string> VNWaitEventParser::getOptionalAttributes() {
+  return { { "duration", "" }, { "time", "" } };
+}
+
+int32_t VNWaitEventParser::onParse(
+  Xml *node,
+  std::map<std::string, std::string> values,
+  VNWaitEvent *out,
+  std::string *error
+) {
+  //Get the duration
+  if(!values["duration"].empty()) {
+    out->duration = values["duration"];
+  } else if(!values["time"].empty()) {
+    out->duration = values["time"];
+  } else {
+    *error = "No duration specified.";
+    return -1;
+  }
+
+  return 0;
+}
\ No newline at end of file
diff --git a/src/dawntools/vnscenetool/events/VNWaitEventParser.hpp b/src/dawntools/vnscenetool/events/VNWaitEventParser.hpp
new file mode 100644
index 00000000..75d2bf6b
--- /dev/null
+++ b/src/dawntools/vnscenetool/events/VNWaitEventParser.hpp
@@ -0,0 +1,25 @@
+// Copyright (c) 2023 Dominic Masters
+// 
+// This software is released under the MIT License.
+// https://opensource.org/licenses/MIT
+
+#pragma once
+#include "util/XmlParser.hpp"
+
+namespace Dawn {
+  struct VNWaitEvent {
+    std::string duration;
+  };
+
+  class VNWaitEventParser : public XmlParser<VNWaitEvent> {
+    protected:
+      std::vector<std::string> getRequiredAttributes() override;
+      std::map<std::string, std::string> getOptionalAttributes() override;
+      int32_t onParse(
+        Xml *node,
+        std::map<std::string, std::string> values,
+        VNWaitEvent *out,
+        std::string *error
+      ) override;
+  };
+}
\ No newline at end of file