| 151 | } |
| 152 | |
| 153 | std::vector<::Generators::Compose> ScriptAPI::parseComposition(const sol::object& object, bool requireFraction) const { |
| 154 | if (!object.is<sol::table>()) { |
| 155 | throw std::runtime_error("composition must be a table"); |
| 156 | } |
| 157 | |
| 158 | const sol::table table = object.as<sol::table>(); |
| 159 | std::vector<::Generators::Compose> composition; |
| 160 | for (const auto& entry : table) { |
| 161 | const sol::object value = entry.second.as<sol::object>(); |
| 162 | if (!value.is<sol::table>()) { |
| 163 | throw std::runtime_error("composition entries must be tables"); |
| 164 | } |
| 165 | |
| 166 | const sol::table item = value.as<sol::table>(); |
| 167 | ::Generators::Compose compose; |
| 168 | compose.species = item.get_or("name", item.get_or("element", std::string{})); |
| 169 | if (compose.species.empty()) { |
| 170 | throw std::runtime_error("composition entry requires name or element"); |
| 171 | } |
| 172 | compose.fraction = requireFraction ? item.get_or("fraction", 0.0f) : item.get_or("fraction", 1.0f); |
| 173 | if (compose.fraction <= 0.0f) { |
| 174 | throw std::runtime_error("composition fraction must be > 0"); |
| 175 | } |
| 176 | composition.push_back(std::move(compose)); |
| 177 | } |
| 178 | |
| 179 | if (composition.empty()) { |
| 180 | throw std::runtime_error("composition must not be empty"); |
| 181 | } |
| 182 | return composition; |
| 183 | } |
| 184 | |
| 185 | std::unique_ptr<Generators::Region> ScriptAPI::parseRegion(const sol::object& object) const { |
| 186 | if (!object.is<sol::table>()) { |