h2-mod/src/client/game/ui_scripting/script_value.hpp

260 lines
4.8 KiB
C++
Raw Normal View History

2021-10-21 00:21:50 +02:00
#pragma once
#include "game/game.hpp"
2022-04-28 22:41:29 +02:00
#include <utils/string.hpp>
2021-10-21 00:21:50 +02:00
namespace ui_scripting
{
class lightuserdata;
2022-04-28 22:41:29 +02:00
class userdata_value;
2021-10-21 00:21:50 +02:00
class userdata;
2022-04-28 22:41:29 +02:00
class table_value;
2021-10-21 00:21:50 +02:00
class table;
class function;
2022-04-28 22:41:29 +02:00
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>;
2021-10-21 00:21:50 +02:00
class script_value
{
public:
script_value() = default;
script_value(const game::hks::HksObject& value);
script_value(int value);
script_value(unsigned int value);
2022-04-28 22:41:29 +02:00
script_value(long long value);
script_value(unsigned long long value);
2021-10-21 00:21:50 +02:00
script_value(bool value);
script_value(float value);
script_value(double value);
script_value(const char* value);
2022-01-31 08:48:56 +01:00
script_value(const char* value, unsigned int len);
2021-10-21 00:21:50 +02:00
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);
2022-04-28 22:41:29 +02:00
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};
}
2021-10-21 00:21:50 +02:00
template <typename T>
bool is() const;
template <typename T>
T as() const
{
if (!this->is<T>())
{
2022-05-02 01:05:16 +02:00
const auto hks_typename = game::hks::typenames[this->get_raw().t + 2];
const auto typename_ = get_typename<T>();
2022-04-28 22:41:29 +02:00
throw std::runtime_error(utils::string::va("%s expected, got %s",
2022-05-02 01:05:16 +02:00
typename_.data(), hks_typename));
2021-10-21 00:21:50 +02:00
}
return get<T>();
}
2022-04-28 22:41:29 +02:00
template <typename T>
operator T() const
{
return this->as<T>();
}
2021-10-21 00:21:50 +02:00
const game::hks::HksObject& get_raw() const;
2022-04-28 22:41:29 +02:00
hks_object value_{};
2022-05-02 01:05:16 +02:00
private:
2021-10-21 00:21:50 +02:00
template <typename T>
T get() const;
};
2022-04-28 22:41:29 +02:00
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
{
2022-05-02 01:05:16 +02:00
try
2022-04-28 22:41:29 +02:00
{
2022-05-02 01:05:16 +02:00
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()));
2022-04-28 22:41:29 +02:00
}
}
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_{};
};
2021-10-21 00:21:50 +02:00
}