260 lines
4.8 KiB
C++
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_{};
|
|
};
|
|
}
|