#pragma once #include "game/game.hpp" #include namespace ui_scripting { class lightuserdata; class userdata_value; class userdata; class table_value; class table; class function; class script_value; namespace { template std::string get_typename() { auto& info = typeid(T); if (info == typeid(std::string) || info == typeid(const char*)) { return "string"; } if (info == typeid(lightuserdata)) { return "lightuserdata"; } if (info == typeid(userdata)) { return "userdata"; } if (info == typeid(table)) { return "table"; } if (info == typeid(function)) { return "function"; } if (info == typeid(int) || info == typeid(float) || info == typeid(unsigned int)) { return "number"; } if (info == typeid(bool)) { return "boolean"; } return info.name(); } } class hks_object { public: hks_object() = default; hks_object(const game::hks::HksObject& value); hks_object(const hks_object& other) noexcept; hks_object(hks_object&& other) noexcept; hks_object& operator=(const hks_object& other) noexcept; hks_object& operator=(hks_object&& other) noexcept; ~hks_object(); const game::hks::HksObject& get() const; private: void assign(const game::hks::HksObject& value); void release(); game::hks::HksObject value_{game::hks::TNONE, {}}; int ref_{}; }; using arguments = std::vector; using event_arguments = std::unordered_map; class script_value { public: script_value() = default; script_value(const game::hks::HksObject& value); script_value(int value); script_value(unsigned int value); script_value(long long value); script_value(unsigned long long value); script_value(bool value); script_value(float value); script_value(double value); script_value(const char* value); script_value(const char* value, unsigned int len); script_value(const std::string& value); script_value(const lightuserdata& value); script_value(const userdata& value); script_value(const table& value); script_value(const function& value); template class C, class T, typename TableType = table> script_value(const C>& container) { TableType table_{}; int index = 1; for (const auto& value : container) { table_.set(index++, value); } game::hks::HksObject obj{}; obj.t = game::hks::TTABLE; obj.v.ptr = table_.ptr; this->value_ = obj; } template script_value(F f) : script_value(function(f)) { } bool operator==(const script_value& other) const; arguments operator()() const; arguments operator()(const arguments& arguments) const; template arguments operator()(T... arguments) const { return this->as().call({arguments...}); } template table_value operator[](const char(&key)[Size]) const { return {this->as(), key}; } template table_value operator[](const T& key) const { return {this->as
(), key}; } template bool is() const; template T as() const { if (!this->is()) { throw std::runtime_error(utils::string::va("%s expected, got %s", typeid(T).name(), game::hks::typenames[this->get_raw().t + 2])); } return get(); } template operator T() const { return this->as(); } const game::hks::HksObject& get_raw() const; hks_object value_{}; template T get() const; }; class variadic_args : public arguments { }; class function_argument { public: function_argument(const arguments& args, const script_value& value, const int index); template T as() const { if (!this->value_.is()) { const auto hks_typename = game::hks::typenames[this->value_.get_raw().t + 2]; const auto typename_ = get_typename(); throw std::runtime_error(utils::string::va("bad argument #%d (%s expected, got %s)", this->index_ + 1, typename_.data(), hks_typename)); } return this->value_.get(); } template <> variadic_args as() const { variadic_args args{}; for (auto i = this->index_; i < this->values_.size(); i++) { args.push_back(this->values_[i]); } return args; } template operator T() const { return this->as(); } private: arguments values_{}; script_value value_{}; int index_{}; }; class function_arguments { public: function_arguments(const arguments& values); function_argument operator[](const int index) const { if (index >= values_.size()) { return {values_, {}, index}; } return {values_, values_[index], index}; } private: arguments values_{}; }; }