From 7d71827c25ff1ab47c03aaa26f63a9a754b3d549 Mon Sep 17 00:00:00 2001
From: Jon Santmyer <jon@jonsantmyer.com>
Date: Sun, 3 Jul 2022 11:24:05 -0400
Subject: Condensed solar system csv files into one.

Add argument parser for help and different systems
---
 src/diargs.cpp | 84 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/game.cpp   |  9 +++----
 src/main.cpp   | 27 ++++++++++++++++---
 src/system.cpp | 73 ++++++++++++++++----------------------------------
 4 files changed, 135 insertions(+), 58 deletions(-)
 create mode 100644 src/diargs.cpp

(limited to 'src')

diff --git a/src/diargs.cpp b/src/diargs.cpp
new file mode 100644
index 0000000..b7aa79e
--- /dev/null
+++ b/src/diargs.cpp
@@ -0,0 +1,84 @@
+/**
+ * diargs.cpp
+ * Copyright (c) 2022 Jon Santmyer <jon@jonsantmyer.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#include "diargs.hpp"
+#include <string_view>
+#include <list>
+
+namespace diargs
+{
+
+ArgumentParser::ArgumentParser(
+        void (*failfunc)(int), 
+        ArgumentList &arguments,
+        ArgsPair argcv)
+{
+    /*Raw c strings passed to string_view for safety*/
+    std::vector<std::string_view> argv(argcv.argc);
+    for(int arg = 0; arg < argcv.argc; arg++) {
+        argv[arg] = std::string_view(argcv.argv[arg]);
+    }
+
+    /*Skip the first argument because it will always be the path to the program*/
+    for(auto it = argv.begin() + 1; it != argv.end(); it++) {
+        if(it->at(0) == '-') { /*Argument could be shortform*/
+            if(it->at(1) == '-') { /*Argument is longform*/
+                std::string_view parsing = std::string_view(it->data() + 2);
+                if(parsing.size() == 0) continue;
+                for(auto &argdef : arguments.arguments) {
+                    if(argdef->longform != parsing) continue;
+                    auto newit = argdef->parse(argv, it);
+                    if(newit == std::nullopt) {
+                        failfunc(-1);
+                        return;
+                    }
+                    it = newit.value_or(argv.end());
+                    break;
+                }
+                continue;
+            }
+            std::string_view parsing = (*it);
+            for(char c : parsing) {
+                for(auto &argdef : arguments.arguments) {
+                    if(argdef->shortform != c) continue;
+                    auto newit = argdef->parse(argv, it);
+                    if(newit == std::nullopt) {
+                        failfunc(-1);
+                        return;
+                    }
+                    it = newit.value_or(argv.end());
+                }
+            }
+            continue;
+        } /*When argument is unmarked, it's an ordered type*/
+        for(auto argit = arguments.arguments.begin(); 
+                argit != arguments.arguments.end();
+                argit++) {
+            if((*argit)->shortform != 0 || !(*argit)->longform.empty()) continue;
+            it = (*argit)->parse(argv, it).value_or(argv.end());
+            arguments.arguments.erase(argit);
+            break;
+        }
+    }
+}
+
+}
diff --git a/src/game.cpp b/src/game.cpp
index b1d0b00..d992a99 100644
--- a/src/game.cpp
+++ b/src/game.cpp
@@ -21,7 +21,7 @@ Game::State Game::m_state = State::RUNNING;
 Game::WindowContexts Game::contexts;
 
 void
-Game::setup(unsigned w, unsigned h)
+Game::setup(unsigned w, unsigned h, const std::string &sysname)
 {
     KeyMan::loadKeybindsFrom("keybinds.csv");
 
@@ -32,22 +32,21 @@ Game::setup(unsigned w, unsigned h)
     unsigned int viewh = h - 1;
     unsigned int infow = 24;
     unsigned int infoh = 12;
-    unsigned int timeh = 10;
+    unsigned int timeh = h - infoh;
 
     TimeMan::init();
     m_contexts.emplace(WINCTX_GAME, WindowContext());
+    m_contexts.emplace(WINCTX_TITLE, WindowContext());
     WindowContext *gameContext = &m_contexts[WINCTX_GAME];
 
     gameContext->registerWindow(WINDOW_SYSTEMVIEW_ID, "System View", infow, 0, w - infow, viewh);
     gameContext->registerWindow(WINDOW_BODYINFO_ID, "Body Info", 0, 0, infow, infoh);
-    gameContext->registerWindow(WINDOW_EVENTS_ID, "Events", 0, infoh, infow, viewh - infoh - timeh);
     gameContext->registerWindow(WINDOW_TIMEMAN_ID, "Time", 0, viewh - timeh, infow, timeh);
-
     gameContext->registerWindow(WINDOW_SYSTEMVIEW_SEARCH_ID, "Search", infow, 0, (w - infow) / 4, viewh, true);
     m_currentContext = WINCTX_GAME;
 
     m_camera = std::make_unique<Camera>((*gameContext)[WINDOW_SYSTEMVIEW_ID].screen());
-    m_system = std::make_unique<System>();
+    m_system = std::make_unique<System>(sysname);
     m_systemView.view(m_system.get());
 
     KeyMan::registerBind('\x1B', BIND_G_ESCAPE, CTX_GLOBAL, "Escape from focused searchbox / window");
diff --git a/src/main.cpp b/src/main.cpp
index 9ff09a6..5fafaf8 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -1,21 +1,42 @@
 #include <iostream>
 #include "game.hpp"
+#include "diargs.hpp"
 
 #include <sys/ioctl.h>
 #include <fcntl.h>
 #include <unistd.h>
 
+void
+printusage(int err)
+{
+    std::cout << "systemviewer " << VERSION << std::endl << 
+        "Usage: systemviewer [OPTION]... [FILE]" << std::endl << 
+        "With no FILE, FILE is assumed to be data/sol.csv" << std::endl <<
+        "-h --help : print this message" << std::endl;
+
+    std::exit(err);
+}
+
 int
 main(int argc, char **argv)
 {
-    (void)argc;
-    (void)argv;
+    std::string system = "dat/sol.csv";
+    bool helpflag;
+
+    diargs::ArgsPair args{argc, argv};
+    diargs::ArgumentList arglist(
+        diargs::OrderedArgument<std::string>(system),
+        diargs::ToggleArgument<bool>("help", 'h', helpflag, true)
+            );
+    diargs::ArgumentParser(printusage, arglist, args);
+
+    if(helpflag) printusage(0);
 
     struct winsize w;
     ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
     fcntl(STDIN_FILENO, F_SETFL, fcntl(0, F_GETFL) | O_NONBLOCK);
 
-    Game::setup(w.ws_col, w.ws_row);
+    Game::setup(w.ws_col, w.ws_row, system);
 
     while(Game::running()) {
         Game::turn();
diff --git a/src/system.cpp b/src/system.cpp
index 974d0dc..61cb8be 100644
--- a/src/system.cpp
+++ b/src/system.cpp
@@ -11,7 +11,7 @@
 
 static double G = 6.6743 * std::pow(10, -11);
 
-ecs::Entity &
+void
 System::addOrbital(const std::string &name, 
            const std::string &orbitingName, 
            unsigned long a, 
@@ -25,64 +25,36 @@ System::addOrbital(const std::string &name,
     w *= (std::numbers::pi / 180.0);
 
     SystemTreeNode *treeNode = getNode(orbitingName);
-    ecs::Entity &newOrbital = m_entityMan.newEntity()
+    ecs::Entity newOrbital = m_entityMan.newEntity()
         .addComponent(ecs::PositionComponent{vex::vec2<long>{0, 0}})
         .addComponent(ecs::MassComponent{m})
-        .addComponent(ecs::OrbitalComponent{.origin = treeNode->entityId, .a = (long)a, .e = e, .w = w, .M = M, .T = 0, .v = 0})
         .addComponent(ecs::RenderCircleComponent{r})
         .addComponent(ecs::NameComponent{name});
-    treeNode->children.push_back({newOrbital.id, {}});
-    return newOrbital;
+    if(treeNode != nullptr) {
+        newOrbital.addComponent(ecs::OrbitalComponent{.origin = (unsigned)treeNode->entityId, .a = (long)a, .e = e, .w = w, .M = M, .T = 0, .v = 0});
+        treeNode->children.push_back({(int)newOrbital.id, {}});
+    }else{
+        m_systemTree.entityId = newOrbital.id;
+    }
 }
 
-System::System()
+System::System(const std::string &name)
 {
-    auto sol = m_entityMan.newEntity()
-        .addComponent(ecs::PositionComponent{vex::vec2<long>{0, 0}})
-        .addComponent(ecs::MassComponent{unit::solMass})
-        .addComponent(ecs::RenderCircleComponent{695700})
-        .addComponent(ecs::NameComponent{"Sol"});
-    m_systemTree.entityId = sol.id;
-
-    csv::CSVFile<',', std::string, std::string, double, double, double, double, double, double> planetData("data/sol_planets.csv");
-    for(auto &planet : planetData.get()) {
-        std::string name = std::get<0>(planet);
-        std::string orbiting = std::get<1>(planet);
-        double sma = std::get<2>(planet) * unit::AU;
-        double e = std::get<3>(planet);
-        unit::Mass m = unit::earthMass * std::get<4>(planet);
-        double r = std::get<5>(planet) * unit::earthRad;
-        double M = std::get<6>(planet);
-        double w = std::get<7>(planet);
+    m_systemTree.entityId = -1;
+    csv::CSVFile<',', std::string, std::string, double, double, double, double, double, double, std::string> bodyData(name);
+    for(auto &body : bodyData.get()) {
+        std::string name = std::get<0>(body);
+        std::string orbiting = std::get<1>(body);
+        double sma = std::get<2>(body) * unit::AU;
+        double e = std::get<3>(body);
+        unit::Mass m = unit::earthMass * std::get<4>(body);
+        double r = std::get<5>(body) * unit::earthRad;
+        double M = std::get<6>(body);
+        double w = std::get<7>(body);
+
+        if(name == "Missing") name = std::get<8>(body);
         addOrbital(name, orbiting, sma, e, m, r, M, w);
     }
-
-    csv::CSVFile<',', std::string, std::string, double, double, double, double, double, double> satelliteData("data/sol_satellites.csv");
-    for(auto &satellite : satelliteData.get()) {
-        std::string name = std::get<0>(satellite);
-        std::string orbiting = std::get<1>(satellite);
-        double sma = std::get<2>(satellite) * unit::AU;
-        double e = std::get<3>(satellite);
-        unit::Mass m = unit::earthMass * std::get<4>(satellite);
-        double r = std::get<5>(satellite) * unit::earthRad;
-        double M = std::get<6>(satellite);
-        double w = std::get<7>(satellite);
-        addOrbital(name, orbiting, sma, e, m, r, M, w);
-    }
-
-    csv::CSVFile<',', std::string, double, double, double, double, double, std::string> asteroidData("data/sol_asteroids.csv");
-    for(auto &asteroid : asteroidData.get()) {
-        std::string name = std::get<0>(asteroid);
-        if(name == "Missing") name = std::get<6>(asteroid);
-        addOrbital(name, 
-                   "Sol", 
-                   (unsigned long)(std::get<1>(asteroid) * unit::AU),
-                   std::get<2>(asteroid),
-                   unit::Mass(0),
-                   (unsigned)std::get<3>(asteroid),
-                   std::get<4>(asteroid),
-                   std::get<5>(asteroid));
-    }
 }
 
 constexpr static double tau = std::numbers::pi * 2;
@@ -161,6 +133,7 @@ System::traverseSystemTree(SystemTreeNode &node, const std::string &name)
 System::SystemTreeNode *
 System::getNode(const std::string &name)
 {
+    if(m_systemTree.entityId == -1) return nullptr;
     SystemTreeNode *treeRes = traverseSystemTree(m_systemTree, name);
     if(treeRes == nullptr)
         treeRes = &m_systemTree;
-- 
cgit v1.2.1