Organize scripts and add TWS plugins with HTTP timeouts

Vendor pinned T5 and T6 plugin sources under the new plugins layout. Add native HTTP deadlines, status and timing diagnostics, telemetry integration, and build/test tooling.
This commit is contained in:
2026-10-09 11:02:20 -04:00
parent b172086301
commit 1121b44857
253 changed files with 28028 additions and 59 deletions
@@ -0,0 +1,399 @@
#pragma once
#include "game/game.hpp"
#include "variable_value.hpp"
#include "vector.hpp"
#include <utils/string.hpp>
namespace scripting
{
class entity;
class array;
class object;
class function;
class script_value;
namespace
{
std::unordered_map<int, std::string> typenames =
{
{0, "undefined"},
{1, "object"},
{2, "string"},
{3, "localized string"},
{4, "vector"},
{5, "float"},
{6, "int"},
{7, "codepos"},
{8, "precodepos"},
{9, "function"},
{10, "stack"},
{11, "animation"},
{12, "developer codepos"},
{13, "thread"},
{14, "thread"},
{15, "thread"},
{16, "thread"},
{17, "struct"},
{18, "removed entity"},
{19, "entity"},
{20, "array"},
{21, "removed thread"},
};
std::string get_typename(const game::VariableValue& value)
{
auto type_ = 0;
if (value.type == game::SCRIPT_OBJECT)
{
type_ = game::GetObjectType(game::SCRIPTINSTANCE_SERVER, value.u.uintValue);
}
else
{
type_ = value.type;
}
if (typenames.find(type_) != typenames.end())
{
return typenames[type_];
}
return "unknown";
}
template <typename T>
std::string get_c_typename()
{
auto& info = typeid(T);
if (info == typeid(std::string))
{
return "string";
}
if (info == typeid(const char*))
{
return "string";
}
if (info == typeid(entity))
{
return "entity";
}
if (info == typeid(array))
{
return "array";
}
if (info == typeid(object))
{
return "struct";
}
if (info == typeid(function))
{
return "function";
}
if (info == typeid(vector))
{
return "vector";
}
return info.name();
}
}
using arguments = std::vector<script_value>;
class script_value
{
public:
script_value() = default;
script_value(const game::VariableValue& value);
script_value(void* value);
script_value(int value);
script_value(unsigned int value);
script_value(bool value);
script_value(float value);
script_value(double value);
script_value(const char* value);
script_value(const std::string& value);
script_value(const entity& value);
script_value(const array& value);
script_value(const object& value);
script_value(const function& value);
script_value(const vector& value);
private:
template <typename T>
T get() const
{
if constexpr (std::is_pointer<T>::value)
{
if (this->is<unsigned int>())
{
return reinterpret_cast<T>(this->as<unsigned int>());
}
}
if constexpr (std::is_constructible<T, std::string>::value)
{
if (this->is<std::string>())
{
return T(this->as<std::string>());
}
}
throw std::runtime_error("Invalid type");
}
public:
#define ADD_TYPE(type) \
template <> \
bool is<type>() const; \
private: \
template <> \
type get<>() const; \
public: \
template <typename T>
bool is() const
{
if constexpr (std::is_pointer<T>::value)
{
if (this->is<unsigned int>())
{
return true;
}
}
if (std::is_constructible<T, std::string>::value && this->is<std::string>())
{
return true;
}
return false;
}
ADD_TYPE(bool)
ADD_TYPE(int)
ADD_TYPE(unsigned int)
ADD_TYPE(unsigned short)
ADD_TYPE(float)
ADD_TYPE(float*)
ADD_TYPE(double)
ADD_TYPE(const char*)
ADD_TYPE(std::string)
ADD_TYPE(vector)
ADD_TYPE(array)
ADD_TYPE(object)
ADD_TYPE(function)
ADD_TYPE(entity)
ADD_TYPE(script_value)
template <typename T>
T as() const
{
if (!this->is<T>())
{
const auto type = get_typename(this->get_raw());
const auto c_type = get_c_typename<T>();
throw std::runtime_error(utils::string::va("has type '%s' but should be '%s'", type.data(), c_type.data()));
}
return get<T>();
}
template <typename T>
T as_or(const T& default_value) const
{
if (!this->is<T>())
{
return default_value;
}
return get<T>();
}
std::string type_name() const
{
return get_typename(this->get_raw());
}
template <template<class, class> class C, class T, typename ArrayType = array>
script_value(const C<T, std::allocator<T>>& container)
{
ArrayType array_{};
for (const auto& value : container)
{
array_.emplace_back(value);
}
game::VariableValue value{};
value.type = game::SCRIPT_OBJECT;
value.u.pointerValue = array_.get_entity_id();
this->value_ = value;
}
template<class ...T>
arguments operator()(T... arguments) const
{
return this->as<function>().call({arguments...});
}
std::string to_string() const;
friend bool operator==(const script_value& a, const script_value& b)
{
const auto& value_raw_a = a.get_raw();
const auto& value_raw_b = b.get_raw();
return value_raw_a.type != value_raw_b.type && value_raw_a.u.uintValue == value_raw_b.u.uintValue;
}
const game::VariableValue& get_raw() const;
variable_value value_{};
};
class function_argument;
class variadic_args : public std::vector<function_argument>
{
public:
variadic_args(const size_t begin);
function_argument operator[](size_t index) const;
private:
size_t begin_;
};
class function_argument : public script_value
{
public:
function_argument(const arguments& args, const script_value& value, const size_t index, const bool exists);
template <typename T>
T as() const
{
if (!this->exists_)
{
throw std::runtime_error(utils::string::va("parameter %d does not exist", this->index_));
}
try
{
return script_value::as<T>();
}
catch (const std::exception& e)
{
throw std::runtime_error(utils::string::va("parameter %d %s",
this->index_, e.what()));
}
}
template <typename T, typename I = int>
T* as_ptr() const
{
const auto value = script_value::as<I>();
if (value == nullptr)
{
throw std::runtime_error("is null");
}
return reinterpret_cast<T*>(value);
}
template <>
variadic_args as() const
{
variadic_args args{this->index_};
for (auto i = this->index_; i < this->values_.size(); i++)
{
args.emplace_back(this->values_, this->values_[i], i, true);
}
return args;
}
operator variadic_args() const
{
return this->as<variadic_args>();
}
template <template<class, class> class C, class T, class ArrayType = array>
operator C<T, std::allocator<T>>() const
{
const auto container_type = get_c_typename<C<T, std::allocator<T>>>();
if (!script_value::is<ArrayType>())
{
const auto type = get_typename(this->get_raw());
throw std::runtime_error(utils::string::va("has type '%s' but should be '%s'",
type.data(),
container_type.data()
));
}
C<T, std::allocator<T>> container{};
const auto array = script_value::as<ArrayType>();
for (auto i = 0u; i < array.size(); i++)
{
try
{
container.emplace_back(array.get(i).as<T>());
}
catch (const std::exception& e)
{
throw std::runtime_error(utils::string::va("element %d of parameter %d of type '%s' %s",
i, this->index_, container_type.data(), e.what()));
}
}
return container;
}
template <typename T>
operator T() const
{
return this->as<T>();
}
private:
arguments values_{};
size_t index_{};
bool exists_{};
};
class function_arguments
{
public:
function_arguments(const arguments& values);
function_argument operator[](const size_t index) const;
arguments get_raw() const;
size_t size() const;
private:
arguments values_{};
};
}