h2-mod/src/client/game/ui_scripting/script_value.hpp
Federico Cecchetto 4537aff086 Small change
2022-05-02 01:05:16 +02:00

260 lines
4.8 KiB
C++

#pragma once
#include "game/game.hpp"
#include <utils/string.hpp>
namespace ui_scripting
{
class lightuserdata;
class userdata_value;
class userdata;
class table_value;
class table;
class function;
class script_value;
namespace
{
template <typename T>
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<script_value>;
using event_arguments = std::unordered_map<std::string, script_value>;
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 <template<class, class> class C, class T, typename TableType = table>
script_value(const C<T, std::allocator<T>>& 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 <typename F>
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<class ...T>
arguments operator()(T... arguments) const
{
return this->as<function>().call({arguments...});
}
template <size_t Size>
table_value operator[](const char(&key)[Size]) const
{
return {this->as<table>(), key};
}
template <typename T = script_value>
table_value operator[](const T& key) const
{
return {this->as<table>(), key};
}
template <typename T>
bool is() const;
template <typename T>
T as() const
{
if (!this->is<T>())
{
const auto hks_typename = game::hks::typenames[this->get_raw().t + 2];
const auto typename_ = get_typename<T>();
throw std::runtime_error(utils::string::va("%s expected, got %s",
typename_.data(), hks_typename));
}
return get<T>();
}
template <typename T>
operator T() const
{
return this->as<T>();
}
const game::hks::HksObject& get_raw() const;
hks_object value_{};
private:
template <typename T>
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 <typename T>
T as() const
{
try
{
return this->value_.as<T>();
}
catch (const std::exception& e)
{
throw std::runtime_error(utils::string::va("bad argument #%d (%s)",
this->index_ + 1, e.what()));
}
}
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 <typename T>
operator T() const
{
return this->as<T>();
}
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_{};
};
}