💿🐜 Antkeeper source code https://antkeeper.com
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

165 lines
5.7 KiB

  1. /*
  2. * Copyright (C) 2021 Christopher J. Howard
  3. *
  4. * This file is part of Antkeeper source code.
  5. *
  6. * Antkeeper source code is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * Antkeeper source code is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. #include "resource-loader.hpp"
  20. #include "resource-manager.hpp"
  21. #include "entity/ebt.hpp"
  22. #include <nlohmann/json.hpp>
  23. #include <functional>
  24. #include <map>
  25. #include <stdexcept>
  26. #include <iostream>
  27. #include <type_traits>
  28. #include <sstream>
  29. #include <physfs.h>
  30. /*
  31. template <class T>
  32. void parse_argument(T& value, const std::string& string)
  33. {
  34. std::istringstream stream(string);
  35. stream >> value;
  36. }
  37. template <>
  38. void parse_argument(std::string& value, const std::string& string)
  39. {
  40. value = string;
  41. }
  42. template <class T, class... Args>
  43. std::function<entity::ebt::status(entity::ebt::context&)> pack_function(T (*function)(entity::ebt::context&, Args...), std::list<std::string> argv)
  44. {
  45. //if (argv.size() != sizeof...(Args))
  46. // Parse list of strings into tuple of arguments
  47. std::tuple<std::decay_t<Args>...> arguments;
  48. if constexpr (sizeof...(Args) > 0)
  49. {
  50. std::apply([&argv](auto& element, auto&... elements)
  51. {
  52. parse_argument(element, argv.front());
  53. argv.pop_front();
  54. },
  55. arguments);
  56. }
  57. return std::bind(
  58. [function, arguments](entity::ebt::context& context) -> entity::ebt::status
  59. {
  60. return std::apply(function, std::tuple_cat(std::make_tuple(context), arguments));
  61. },
  62. std::placeholders::_1);
  63. }
  64. static entity::ebt::node* load_node(const nlohmann::json::const_iterator& json, resource_manager* resource_manager);
  65. static void load_node_child(entity::ebt::decorator_node* node, const nlohmann::json& json, resource_manager* resource_manager);
  66. static void load_node_children(entity::ebt::composite_node* node, const nlohmann::json& json, resource_manager* resource_manager);
  67. static entity::ebt::node* load_action_node(const nlohmann::json& json, resource_manager* resource_manager)
  68. {
  69. // Get function name
  70. auto function_it = json.find("function");
  71. if (function_it == json.end())
  72. throw std::runtime_error("load_action_node(): Action node has no function.");
  73. std::string function_name = function_it.value().get<std::string>();
  74. // Get argument vector
  75. std::list<std::string> arguments;
  76. auto arguments_it = json.find("arguments");
  77. for (auto it = arguments_it.value().cbegin(); it != arguments_it.value().cend(); ++it)
  78. arguments.push_back(it.value().get<std::string>());
  79. entity::ebt::action* action_node = new entity::ebt::action();
  80. if (function_name == "print") action_node->function = pack_function(entity::ebt::print, arguments);
  81. else if (function_name == "print_eid") action_node->function = pack_function(entity::ebt::print_eid, arguments);
  82. else if (function_name == "warp_to") action_node->function = pack_function(entity::ebt::warp_to, arguments);
  83. return action_node;
  84. }
  85. static entity::ebt::node* load_selector_node(const nlohmann::json& json, resource_manager* resource_manager)
  86. {
  87. entity::ebt::selector* selector_node = new entity::ebt::selector();
  88. load_node_children(selector_node, json, resource_manager);
  89. return selector_node;
  90. }
  91. static entity::ebt::node* load_sequence_node(const nlohmann::json& json, resource_manager* resource_manager)
  92. {
  93. entity::ebt::sequence* sequence_node = new entity::ebt::sequence();
  94. load_node_children(sequence_node, json, resource_manager);
  95. return sequence_node;
  96. }
  97. static entity::ebt::node* load_node(const nlohmann::json::const_iterator& json, resource_manager* resource_manager)
  98. {
  99. static const std::map<std::string, std::function<entity::ebt::node*(const nlohmann::json&, ::resource_manager*)>> node_loaders =
  100. {
  101. {"action", &load_action_node},
  102. {"selector", &load_selector_node},
  103. {"sequence", &load_sequence_node}
  104. };
  105. auto node_loader = node_loaders.find(json.key());
  106. if (node_loader == node_loaders.end())
  107. {
  108. throw std::runtime_error("load_node(): Unknown behavior tree node type \"" + json.key() + "\"");
  109. }
  110. return node_loader->second(json.value(), resource_manager);
  111. }
  112. static void load_node_child(entity::ebt::decorator_node* node, const nlohmann::json& json, resource_manager* resource_manager)
  113. {
  114. auto it = json.find("child");
  115. node->child = load_node(it.value().cbegin(), resource_manager);
  116. }
  117. static void load_node_children(entity::ebt::composite_node* node, const nlohmann::json& json, resource_manager* resource_manager)
  118. {
  119. auto children_it = json.find("children");
  120. for (auto it = children_it.value().cbegin(); it != children_it.value().cend(); ++it)
  121. {
  122. entity::ebt::node* child = load_node(it.value().begin(), resource_manager);
  123. node->children.push_back(child);
  124. }
  125. }
  126. template <>
  127. entity::ebt::node* resource_loader<entity::ebt::node>::load(resource_manager* resource_manager, PHYSFS_File* file, const std::filesystem::path& path)
  128. {
  129. // Read file into buffer
  130. std::size_t size = static_cast<int>(PHYSFS_fileLength(file));
  131. std::string buffer;
  132. buffer.resize(size);
  133. PHYSFS_readBytes(file, &buffer[0], size);
  134. // Parse json from file buffer
  135. nlohmann::json json = nlohmann::json::parse(buffer);
  136. if (json.size() != 1)
  137. {
  138. throw std::runtime_error("resource_loader<entity::ebt::node>::load(): Behavior tree must have exactly one root node.");
  139. }
  140. return load_node(json.cbegin(), resource_manager);
  141. }
  142. */