1
0
mirror of https://github.com/VCMP-SqMod/SqMod.git synced 2025-07-06 00:47:11 +02:00

14 Commits

Author SHA1 Message Date
483ac37bdb Update CMakeLists.txt
Some checks reported errors
continuous-integration/drone/push Build was killed
2022-10-04 02:29:05 +03:00
78dc76e6b4 Object to typename helper. 2022-10-03 18:32:06 +03:00
e29070af49 Update Official.cpp 2022-10-03 18:31:48 +03:00
1f25b3ea60 Update sqratUtil.h 2022-10-03 18:31:36 +03:00
52cfa235be Update JSON.hpp
Some checks reported errors
continuous-integration/drone/push Build was killed
2022-10-02 21:47:20 +03:00
ec7f1183d8 Basic hooking into json parsing.
Also allow customization of the fallback meta-method.
2022-10-02 21:24:12 +03:00
a788e059a5 Implement _tojson meta-method for base types. 2022-09-18 15:02:39 +03:00
5f20ffc4de Remove the manual comma. 2022-09-17 23:49:37 +03:00
08106156c4 Don't add comma for the root container. 2022-09-17 23:42:48 +03:00
60119ff8fa Include comma after separator braces. 2022-09-17 23:41:43 +03:00
f4720ae77a Implement custom types in JSON. 2022-09-17 23:25:16 +03:00
c9fb257f48 Update ThreadPool.hpp 2022-09-15 23:03:50 +03:00
475a428366 Update Data.hpp 2022-09-15 23:03:44 +03:00
42ac0e32b7 Implement JSON serialization.
Just the basics.
2022-09-15 23:03:38 +03:00
31 changed files with 1362 additions and 136 deletions

View File

@ -4,6 +4,7 @@
#include "Base/DynArg.hpp"
#include "Core/Buffer.hpp"
#include "Core/Utility.hpp"
#include "Library/JSON.hpp"
// ------------------------------------------------------------------------------------------------
namespace SqMod {
@ -300,6 +301,21 @@ String AABB::ToString() const
return fmt::format("{},{},{},{},{},{}", min.x, min.y, min.z, max.x, max.y, max.z);
}
// ------------------------------------------------------------------------------------------------
void AABB::ToJSON(CtxJSON & ctx) const
{
if (ctx.mObjectOverArray)
{
fmt::format_to(std::back_inserter(ctx.mOutput), "{{min:{{x:{},y:{},z:{}}},max:{{x:{},y:{},z:{}}},",
min.x, min.y, min.z, max.x, max.y, max.z);
}
else
{
fmt::format_to(std::back_inserter(ctx.mOutput), "{{min:[{},{},{}],max:[{},{},{}]}},",
min.x, min.y, min.z, max.x, max.y, max.z);
}
}
// ------------------------------------------------------------------------------------------------
void AABB::SetStr(SQChar delim, StackStrF & values)
{
@ -793,6 +809,7 @@ void Register_AABB(HSQUIRRELVM vm)
.SquirrelFunc(_SC("cmp"), &SqDynArgFwd< SqDynArgCmpFn< AABB >, SQFloat, SQInteger, bool, std::nullptr_t, AABB >)
.SquirrelFunc(_SC("_typename"), &Typename::Fn)
.Func(_SC("_tostring"), &AABB::ToString)
.Func(_SC("_tojson"), &AABB::ToJSON)
// Meta-methods
.SquirrelFunc(_SC("_add"), &SqDynArgFwd< SqDynArgAddFn< AABB >, SQFloat, SQInteger, bool, std::nullptr_t, AABB >)
.SquirrelFunc(_SC("_sub"), &SqDynArgFwd< SqDynArgSubFn< AABB >, SQFloat, SQInteger, bool, std::nullptr_t, AABB >)

View File

@ -304,6 +304,11 @@ struct AABB
*/
SQMOD_NODISCARD String ToString() const;
/* --------------------------------------------------------------------------------------------
* Used by the script engine to convert an instance of this type to a JSON string.
*/
void ToJSON(CtxJSON & ctx) const;
/* --------------------------------------------------------------------------------------------
* Set the values extracted from the specified string using the specified delimiter.
*/

View File

@ -3,6 +3,7 @@
#include "Base/DynArg.hpp"
#include "Core/Buffer.hpp"
#include "Core/Utility.hpp"
#include "Library/JSON.hpp"
#include "Library/Numeric/Random.hpp"
// ------------------------------------------------------------------------------------------------
@ -360,6 +361,19 @@ String Circle::ToString() const
return fmt::format("{},{},{}", pos.x, pos.y, rad);
}
// ------------------------------------------------------------------------------------------------
void Circle::ToJSON(CtxJSON & ctx) const
{
if (ctx.mObjectOverArray)
{
fmt::format_to(std::back_inserter(ctx.mOutput), "{{x:{},y:{},r:{}}},", pos.x, pos.y, rad);
}
else
{
fmt::format_to(std::back_inserter(ctx.mOutput), "[{},{},{}],", pos.x, pos.y, rad);
}
}
// ------------------------------------------------------------------------------------------------
void Circle::SetRadius(Value nr)
{
@ -552,6 +566,7 @@ void Register_Circle(HSQUIRRELVM vm)
.SquirrelFunc(_SC("cmp"), &SqDynArgFwd< SqDynArgCmpFn< Circle >, SQFloat, SQInteger, bool, std::nullptr_t, Circle >)
.SquirrelFunc(_SC("_typename"), &Typename::Fn)
.Func(_SC("_tostring"), &Circle::ToString)
.Func(_SC("_toJSON"), &Circle::ToJSON)
// Meta-methods
.SquirrelFunc(_SC("_add"), &SqDynArgFwd< SqDynArgAddFn< Circle >, SQFloat, SQInteger, bool, std::nullptr_t, Circle >)
.SquirrelFunc(_SC("_sub"), &SqDynArgFwd< SqDynArgSubFn< Circle >, SQFloat, SQInteger, bool, std::nullptr_t, Circle >)

View File

@ -341,6 +341,11 @@ struct Circle
*/
SQMOD_NODISCARD String ToString() const;
/* --------------------------------------------------------------------------------------------
* Used by the script engine to convert an instance of this type to a JSON string.
*/
void ToJSON(CtxJSON & ctx) const;
/* --------------------------------------------------------------------------------------------
* Set the specified radius.
*/

View File

@ -4,6 +4,7 @@
#include "Base/DynArg.hpp"
#include "Core/Buffer.hpp"
#include "Core/Utility.hpp"
#include "Library/JSON.hpp"
#include "Library/Numeric/Random.hpp"
// ------------------------------------------------------------------------------------------------
@ -481,6 +482,19 @@ String Color3::ToString() const
return fmt::format("{},{},{}", r, g, b);
}
// ------------------------------------------------------------------------------------------------
void Color3::ToJSON(CtxJSON & ctx) const
{
if (ctx.mObjectOverArray)
{
fmt::format_to(std::back_inserter(ctx.mOutput), "{{r:{},g:{},b:{}}},", r, g, b);
}
else
{
fmt::format_to(std::back_inserter(ctx.mOutput), "[{},{},{}],", r, g, b);
}
}
// ------------------------------------------------------------------------------------------------
void Color3::SetScalar(Value ns)
{
@ -741,6 +755,7 @@ void Register_Color3(HSQUIRRELVM vm)
.SquirrelFunc(_SC("cmp"), &SqDynArgFwd< SqDynArgCmpFn< Color3 >, SQFloat, SQInteger, bool, std::nullptr_t, Color3 >)
.SquirrelFunc(_SC("_typename"), &Typename::Fn)
.Func(_SC("_tostring"), &Color3::ToString)
.Func(_SC("_tojson"), &Color3::ToJSON)
// Meta-methods
.SquirrelFunc(_SC("_add"), &SqDynArgFwd< SqDynArgAddFn< Color3 >, SQFloat, SQInteger, bool, std::nullptr_t, Color3 >)
.SquirrelFunc(_SC("_sub"), &SqDynArgFwd< SqDynArgSubFn< Color3 >, SQFloat, SQInteger, bool, std::nullptr_t, Color3 >)

View File

@ -405,6 +405,11 @@ struct Color3
*/
SQMOD_NODISCARD String ToString() const;
/* --------------------------------------------------------------------------------------------
* Used by the script engine to convert an instance of this type to a JSON string.
*/
void ToJSON(CtxJSON & ctx) const;
/* --------------------------------------------------------------------------------------------
* Set all components to the specified scalar value.
*/

View File

@ -4,6 +4,7 @@
#include "Base/DynArg.hpp"
#include "Core/Buffer.hpp"
#include "Core/Utility.hpp"
#include "Library/JSON.hpp"
#include "Library/Numeric/Random.hpp"
// ------------------------------------------------------------------------------------------------
@ -506,6 +507,19 @@ String Color4::ToString() const
return fmt::format("{},{},{},{}", r, g, b, a);
}
// ------------------------------------------------------------------------------------------------
void Color4::ToJSON(CtxJSON & ctx) const
{
if (ctx.mObjectOverArray)
{
fmt::format_to(std::back_inserter(ctx.mOutput), "{{r:{},g:{},b:{},a:{}}},", r, g, b, a);
}
else
{
fmt::format_to(std::back_inserter(ctx.mOutput), "[{},{},{},{}],", r, g, b, a);
}
}
// ------------------------------------------------------------------------------------------------
void Color4::SetScalar(Value ns)
{
@ -781,6 +795,7 @@ void Register_Color4(HSQUIRRELVM vm)
.SquirrelFunc(_SC("cmp"), &SqDynArgFwd< SqDynArgCmpFn< Color4 >, SQFloat, SQInteger, bool, std::nullptr_t, Color4 >)
.SquirrelFunc(_SC("_typename"), &Typename::Fn)
.Func(_SC("_tostring"), &Color4::ToString)
.Func(_SC("_tojson"), &Color4::ToJSON)
// Meta-methods
.SquirrelFunc(_SC("_add"), &SqDynArgFwd< SqDynArgAddFn< Color4 >, SQFloat, SQInteger, bool, std::nullptr_t, Color4 >)
.SquirrelFunc(_SC("_sub"), &SqDynArgFwd< SqDynArgSubFn< Color4 >, SQFloat, SQInteger, bool, std::nullptr_t, Color4 >)

View File

@ -405,6 +405,11 @@ struct Color4
*/
SQMOD_NODISCARD String ToString() const;
/* --------------------------------------------------------------------------------------------
* Used by the script engine to convert an instance of this type to a JSON string.
*/
void ToJSON(CtxJSON & ctx) const;
/* --------------------------------------------------------------------------------------------
* Set all components to the specified scalar value.
*/

View File

@ -5,6 +5,7 @@
#include "Base/DynArg.hpp"
#include "Core/Buffer.hpp"
#include "Core/Utility.hpp"
#include "Library/JSON.hpp"
#include "Library/Numeric/Random.hpp"
// ------------------------------------------------------------------------------------------------
@ -349,6 +350,19 @@ String Quaternion::ToString() const
return fmt::format("{},{},{},{}", x, y, z, w);
}
// ------------------------------------------------------------------------------------------------
void Quaternion::ToJSON(CtxJSON & ctx) const
{
if (ctx.mObjectOverArray)
{
fmt::format_to(std::back_inserter(ctx.mOutput), "{{x:{},y:{},z:{},w:{}}},", x, y, z, w);
}
else
{
fmt::format_to(std::back_inserter(ctx.mOutput), "[{},{},{},{}],", x, y, z, w);
}
}
// ------------------------------------------------------------------------------------------------
void Quaternion::SetScalar(Value ns)
{
@ -775,6 +789,7 @@ void Register_Quaternion(HSQUIRRELVM vm)
.SquirrelFunc(_SC("cmp"), &SqDynArgFwd< SqDynArgCmpFn< Quaternion >, SQFloat, SQInteger, bool, std::nullptr_t, Quaternion >)
.SquirrelFunc(_SC("_typename"), &Typename::Fn)
.Func(_SC("_tostring"), &Quaternion::ToString)
.Func(_SC("_tojson"), &Quaternion::ToJSON)
// Meta-methods
.SquirrelFunc(_SC("_add"), &SqDynArgFwd< SqDynArgAddFn< Quaternion >, SQFloat, SQInteger, bool, std::nullptr_t, Quaternion >)
.SquirrelFunc(_SC("_sub"), &SqDynArgFwd< SqDynArgSubFn< Quaternion >, SQFloat, SQInteger, bool, std::nullptr_t, Quaternion >)

View File

@ -296,6 +296,11 @@ struct Quaternion
*/
SQMOD_NODISCARD String ToString() const;
/* --------------------------------------------------------------------------------------------
* Used by the script engine to convert an instance of this type to a JSON string.
*/
void ToJSON(CtxJSON & ctx) const;
/* --------------------------------------------------------------------------------------------
* Set all components to the specified scalar value.
*/

View File

@ -6,6 +6,9 @@
// ------------------------------------------------------------------------------------------------
namespace SqMod {
// ------------------------------------------------------------------------------------------------
struct CtxJSON;
/* ------------------------------------------------------------------------------------------------
* Helper constants used by the bas types.
*/

View File

@ -3,6 +3,7 @@
#include "Base/DynArg.hpp"
#include "Core/Buffer.hpp"
#include "Core/Utility.hpp"
#include "Library/JSON.hpp"
#include "Library/Numeric/Random.hpp"
// ------------------------------------------------------------------------------------------------
@ -360,6 +361,19 @@ String Sphere::ToString() const
return fmt::format("{},{},{},{}", pos.x, pos.y, pos.z, rad);
}
// ------------------------------------------------------------------------------------------------
void Sphere::ToJSON(CtxJSON & ctx) const
{
if (ctx.mObjectOverArray)
{
fmt::format_to(std::back_inserter(ctx.mOutput), "{{x:{},y:{},z:{},r:{}}},", pos.x, pos.y, pos.z, rad);
}
else
{
fmt::format_to(std::back_inserter(ctx.mOutput), "[{},{},{},{}],", pos.x, pos.y, pos.z, rad);
}
}
// ------------------------------------------------------------------------------------------------
void Sphere::SetRadius(Value nr)
{
@ -527,6 +541,7 @@ void Register_Sphere(HSQUIRRELVM vm)
.SquirrelFunc(_SC("cmp"), &SqDynArgFwd< SqDynArgCmpFn< Sphere >, SQFloat, SQInteger, bool, std::nullptr_t, Sphere >)
.SquirrelFunc(_SC("_typename"), &Typename::Fn)
.Func(_SC("_tostring"), &Sphere::ToString)
.Func(_SC("_tojson"), &Sphere::ToJSON)
// Meta-methods
.SquirrelFunc(_SC("_add"), &SqDynArgFwd< SqDynArgAddFn< Sphere >, SQFloat, SQInteger, bool, std::nullptr_t, Sphere >)
.SquirrelFunc(_SC("_sub"), &SqDynArgFwd< SqDynArgSubFn< Sphere >, SQFloat, SQInteger, bool, std::nullptr_t, Sphere >)

View File

@ -341,6 +341,11 @@ struct Sphere
*/
SQMOD_NODISCARD String ToString() const;
/* --------------------------------------------------------------------------------------------
* Used by the script engine to convert an instance of this type to a JSON string.
*/
void ToJSON(CtxJSON & ctx) const;
/* --------------------------------------------------------------------------------------------
* Set the specified radius.
*/

View File

@ -4,6 +4,7 @@
#include "Base/DynArg.hpp"
#include "Core/Buffer.hpp"
#include "Core/Utility.hpp"
#include "Library/JSON.hpp"
#include "Library/Numeric/Random.hpp"
// ------------------------------------------------------------------------------------------------
@ -295,6 +296,19 @@ String Vector2::ToString() const
return fmt::format("{},{}", x, y);
}
// ------------------------------------------------------------------------------------------------
void Vector2::ToJSON(CtxJSON & ctx) const
{
if (ctx.mObjectOverArray)
{
fmt::format_to(std::back_inserter(ctx.mOutput), "{{x:{},y:{}}},", x, y);
}
else
{
fmt::format_to(std::back_inserter(ctx.mOutput), "[{},{}],", x, y);
}
}
// ------------------------------------------------------------------------------------------------
void Vector2::SetScalar(Value ns)
{
@ -428,6 +442,7 @@ void Register_Vector2(HSQUIRRELVM vm)
.SquirrelFunc(_SC("cmp"), &SqDynArgFwd< SqDynArgCmpFn< Vector2 >, SQFloat, SQInteger, bool, std::nullptr_t, Vector2 >)
.SquirrelFunc(_SC("_typename"), &Typename::Fn)
.Func(_SC("_tostring"), &Vector2::ToString)
.Func(_SC("_tojson"), &Vector2::ToJSON)
// Meta-methods
.SquirrelFunc(_SC("_add"), &SqDynArgFwd< SqDynArgAddFn< Vector2 >, SQFloat, SQInteger, bool, std::nullptr_t, Vector2 >)
.SquirrelFunc(_SC("_sub"), &SqDynArgFwd< SqDynArgSubFn< Vector2 >, SQFloat, SQInteger, bool, std::nullptr_t, Vector2 >)

View File

@ -285,6 +285,11 @@ struct Vector2
*/
SQMOD_NODISCARD String ToString() const;
/* --------------------------------------------------------------------------------------------
* Used by the script engine to convert an instance of this type to a JSON string.
*/
void ToJSON(CtxJSON & ctx) const;
/* --------------------------------------------------------------------------------------------
* Set all components to the specified scalar value.
*/

View File

@ -4,6 +4,7 @@
#include "Base/DynArg.hpp"
#include "Core/Buffer.hpp"
#include "Core/Utility.hpp"
#include "Library/JSON.hpp"
#include "Library/Numeric/Random.hpp"
// ------------------------------------------------------------------------------------------------
@ -441,6 +442,19 @@ String Vector2i::ToString() const
return fmt::format("{},{}", x, y);
}
// ------------------------------------------------------------------------------------------------
void Vector2i::ToJSON(CtxJSON & ctx) const
{
if (ctx.mObjectOverArray)
{
fmt::format_to(std::back_inserter(ctx.mOutput), "{{x:{},y:{}}},", x, y);
}
else
{
fmt::format_to(std::back_inserter(ctx.mOutput), "[{},{}],", x, y);
}
}
// ------------------------------------------------------------------------------------------------
void Vector2i::SetScalar(Value ns)
{
@ -574,6 +588,7 @@ void Register_Vector2i(HSQUIRRELVM vm)
.SquirrelFunc(_SC("cmp"), &SqDynArgFwd< SqDynArgCmpFn< Vector2i >, SQFloat, SQInteger, bool, std::nullptr_t, Vector2i >)
.SquirrelFunc(_SC("_typename"), &Typename::Fn)
.Func(_SC("_tostring"), &Vector2i::ToString)
.Func(_SC("_tojson"), &Vector2i::ToJSON)
// Meta-methods
.SquirrelFunc(_SC("_add"), &SqDynArgFwd< SqDynArgAddFn< Vector2i >, SQFloat, SQInteger, bool, std::nullptr_t, Vector2i >)
.SquirrelFunc(_SC("_sub"), &SqDynArgFwd< SqDynArgSubFn< Vector2i >, SQFloat, SQInteger, bool, std::nullptr_t, Vector2i >)

View File

@ -390,6 +390,11 @@ struct Vector2i
*/
SQMOD_NODISCARD String ToString() const;
/* --------------------------------------------------------------------------------------------
* Used by the script engine to convert an instance of this type to a JSON string.
*/
void ToJSON(CtxJSON & ctx) const;
/* --------------------------------------------------------------------------------------------
* Set all components to the specified scalar value.
*/

View File

@ -5,6 +5,7 @@
#include "Base/DynArg.hpp"
#include "Core/Buffer.hpp"
#include "Core/Utility.hpp"
#include "Library/JSON.hpp"
#include "Library/Numeric/Random.hpp"
// ------------------------------------------------------------------------------------------------
@ -331,6 +332,19 @@ String Vector3::ToString() const
return fmt::format("{},{},{}", x, y, z);
}
// ------------------------------------------------------------------------------------------------
void Vector3::ToJSON(CtxJSON & ctx) const
{
if (ctx.mObjectOverArray)
{
fmt::format_to(std::back_inserter(ctx.mOutput), "{{x:{},y:{},z:{}}},", x, y, z);
}
else
{
fmt::format_to(std::back_inserter(ctx.mOutput), "[{},{},{}],", x, y, z);
}
}
// ------------------------------------------------------------------------------------------------
void Vector3::SetScalar(Value ns)
{
@ -696,6 +710,7 @@ void Register_Vector3(HSQUIRRELVM vm)
.SquirrelFunc(_SC("cmp"), &SqDynArgFwd< SqDynArgCmpFn< Vector3 >, SQFloat, SQInteger, bool, std::nullptr_t, Vector3 >)
.SquirrelFunc(_SC("_typename"), &Typename::Fn)
.Func(_SC("_tostring"), &Vector3::ToString)
.Func(_SC("_tojson"), &Vector3::ToJSON)
// Meta-methods
.SquirrelFunc(_SC("_add"), &SqDynArgFwd< SqDynArgAddFn< Vector3 >, SQFloat, SQInteger, bool, std::nullptr_t, Vector3 >)
.SquirrelFunc(_SC("_sub"), &SqDynArgFwd< SqDynArgSubFn< Vector3 >, SQFloat, SQInteger, bool, std::nullptr_t, Vector3 >)

View File

@ -297,6 +297,11 @@ struct Vector3
*/
SQMOD_NODISCARD String ToString() const;
/* --------------------------------------------------------------------------------------------
* Used by the script engine to convert an instance of this type to a JSON string.
*/
void ToJSON(CtxJSON & ctx) const;
/* --------------------------------------------------------------------------------------------
* Set all components to the specified scalar value.
*/

View File

@ -5,6 +5,7 @@
#include "Base/DynArg.hpp"
#include "Core/Buffer.hpp"
#include "Core/Utility.hpp"
#include "Library/JSON.hpp"
#include "Library/Numeric/Random.hpp"
// ------------------------------------------------------------------------------------------------
@ -344,6 +345,19 @@ String Vector4::ToString() const
return fmt::format("{},{},{},{}", x, y, z, w);
}
// ------------------------------------------------------------------------------------------------
void Vector4::ToJSON(CtxJSON & ctx) const
{
if (ctx.mObjectOverArray)
{
fmt::format_to(std::back_inserter(ctx.mOutput), "{{x:{},y:{},z:{},w:{}}},", x, y, z, w);
}
else
{
fmt::format_to(std::back_inserter(ctx.mOutput), "[{},{},{},{}],", x, y, z, w);
}
}
// ------------------------------------------------------------------------------------------------
void Vector4::SetScalar(Value ns)
{
@ -526,6 +540,7 @@ void Register_Vector4(HSQUIRRELVM vm)
.SquirrelFunc(_SC("cmp"), &SqDynArgFwd< SqDynArgCmpFn< Vector4 >, SQFloat, SQInteger, bool, std::nullptr_t, Vector4 >)
.SquirrelFunc(_SC("_typename"), &Typename::Fn)
.Func(_SC("_tostring"), &Vector4::ToString)
.Func(_SC("_tojson"), &Vector4::ToJSON)
// Meta-methods
.SquirrelFunc(_SC("_add"), &SqDynArgFwd< SqDynArgAddFn< Vector4 >, SQFloat, SQInteger, bool, std::nullptr_t, Vector4 >)
.SquirrelFunc(_SC("_sub"), &SqDynArgFwd< SqDynArgSubFn< Vector4 >, SQFloat, SQInteger, bool, std::nullptr_t, Vector4 >)

View File

@ -295,6 +295,11 @@ struct Vector4
*/
SQMOD_NODISCARD String ToString() const;
/* --------------------------------------------------------------------------------------------
* Used by the script engine to convert an instance of this type to a JSON string.
*/
void ToJSON(CtxJSON & ctx) const;
/* --------------------------------------------------------------------------------------------
* Set all components to the specified scalar value.
*/

View File

@ -227,7 +227,7 @@ if(WIN32 AND MINGW AND COPY_DEPENDENCIES)
file(COPY "${MINGW_BIN_PATH}/libpq.dll" DESTINATION "${PROJECT_SOURCE_DIR}/bin/deps")
file(COPY "${MINGW_BIN_PATH}/libzstd.dll" DESTINATION "${PROJECT_SOURCE_DIR}/bin/deps")
file(COPY "${MINGW_BIN_PATH}/libpsl-5.dll" DESTINATION "${PROJECT_SOURCE_DIR}/bin/deps")
file(COPY "${MINGW_BIN_PATH}/libffi-7.dll" DESTINATION "${PROJECT_SOURCE_DIR}/bin/deps")
file(COPY "${MINGW_BIN_PATH}/libffi-8.dll" DESTINATION "${PROJECT_SOURCE_DIR}/bin/deps")
file(COPY "${MINGW_BIN_PATH}/libcurl-4.dll" DESTINATION "${PROJECT_SOURCE_DIR}/bin/deps")
file(COPY "${MINGW_BIN_PATH}/libssh2-1.dll" DESTINATION "${PROJECT_SOURCE_DIR}/bin/deps")
file(COPY "${MINGW_BIN_PATH}/libidn2-0.dll" DESTINATION "${PROJECT_SOURCE_DIR}/bin/deps")

View File

@ -248,6 +248,14 @@ String SqTypeName(HSQUIRRELVM vm, SQInteger idx)
return String(val.mPtr, static_cast< size_t >(val.mLen));
}
// ------------------------------------------------------------------------------------------------
String SqTypeName(HSQUIRRELVM vm, LightObj & obj)
{
const StackGuard sg(vm);
sq_pushobject(vm, obj);
return SqTypeName(vm, -1);
}
// ------------------------------------------------------------------------------------------------
LightObj BufferToStrObj(const Buffer & b)
{

View File

@ -242,6 +242,11 @@ SQMOD_NODISCARD const SQChar * SqTypeName(SQObjectType type);
*/
SQMOD_NODISCARD String SqTypeName(HSQUIRRELVM vm, SQInteger idx);
/* ------------------------------------------------------------------------------------------------
* Retrieve the string representation of a certain type from a script object.
*/
SQMOD_NODISCARD String SqTypeName(HSQUIRRELVM vm, LightObj & obj);
/* ------------------------------------------------------------------------------------------------
* Create a script string instance from a buffer.
*/

View File

@ -80,7 +80,7 @@ struct ThreadPoolItem
/* --------------------------------------------------------------------------------------------
* Invoked in main thread by the thread pool after the task was completed.
* If it returns true then it will be put back into the queue to be processed again.
* If the boolean parameter is trye then the thread-pool is in the process of shutting down.
* If the boolean parameter is true then the thread-pool is in the process of shutting down.
*/
SQMOD_NODISCARD virtual bool OnCompleted(bool SQ_UNUSED_ARG(stop)) { return false; }
@ -110,13 +110,13 @@ private:
* Destructor.
*/
~ThreadPool();
public:
// --------------------------------------------------------------------------------------------
using Item = std::unique_ptr< ThreadPoolItem >; // Owning pointer of an item.
private:
// --------------------------------------------------------------------------------------------
using Pool = std::vector< std::thread >; // Worker container.
using Item = std::unique_ptr< ThreadPoolItem >; // Owning pointer of an item.
// --------------------------------------------------------------------------------------------
using Finished = moodycamel::ConcurrentQueue< Item >; // Finished items.
// --------------------------------------------------------------------------------------------
@ -190,6 +190,14 @@ public:
Enqueue(Item{item});
}
/* --------------------------------------------------------------------------------------------
* Queue an item to be processed. Will take ownership of the given pointer!
*/
template < class T > void CastEnqueue(std::unique_ptr< T > && item)
{
Enqueue(Item{std::forward< std::unique_ptr< T > >(item)});
}
/* --------------------------------------------------------------------------------------------
* Queue an item to be processed. Will take ownership of the given pointer!
*/

View File

@ -2,6 +2,7 @@
#include "Library/JSON.hpp"
// ------------------------------------------------------------------------------------------------
#include <sajson.h>
#include <sqratConst.h>
// ------------------------------------------------------------------------------------------------
@ -11,13 +12,10 @@
namespace SqMod {
// ------------------------------------------------------------------------------------------------
static SQInteger SqToJSON(HSQUIRRELVM vm) noexcept
{
return sq_throwerror(vm, _SC("Not implemented yet!"));
}
SQMOD_DECL_TYPENAME(SqCtxJSON, _SC("SqCtxJSON"))
// ------------------------------------------------------------------------------------------------
static SQInteger SqFromJson_Push(HSQUIRRELVM vm, const sajson::value & node) noexcept
static SQInteger SqFromJson_Push(HSQUIRRELVM vm, const sajson::value & node) noexcept // NOLINT(misc-no-recursion)
{
// Operation result
SQInteger r = SQ_OK;
@ -151,11 +149,600 @@ static SQInteger SqFromJSON(HSQUIRRELVM vm) noexcept
return SQ_SUCCEEDED(r) ? 1 : r;
}
// ------------------------------------------------------------------------------------------------
CtxJSON & CtxJSON::OpenArray()
{
// Add the array-begin character
mOutput.push_back('[');
// Go forward one level
Advance();
// Allow chaining
return *this;
}
// ------------------------------------------------------------------------------------------------
CtxJSON & CtxJSON::CloseArray()
{
// If the last character is a comma then replace it
if (mOutput.back() == ',')
{
mOutput.back() = ']';
}
// Append the array-end character
else
{
mOutput.push_back(']');
}
// Move the comma after the closing character
mOutput.push_back(',');
// Go back one level
Retreat();
// Allow chaining
return *this;
}
// ------------------------------------------------------------------------------------------------
CtxJSON & CtxJSON::ReopenArray()
{
// If the last character is a comma then remove it
if (mOutput.back() == ',')
{
mOutput.pop_back();
}
// If the last character is the array-end character then replace it with a comma
if (mOutput.back() == ']')
{
mOutput.back() = ',';
}
// Allow chaining
return *this;
}
// ------------------------------------------------------------------------------------------------
CtxJSON & CtxJSON::OpenObject()
{
// Add the object-begin character
mOutput.push_back('{');
// Go forward one level
Advance();
// Allow chaining
return *this;
}
// ------------------------------------------------------------------------------------------------
CtxJSON & CtxJSON::CloseObject()
{
// If the last character is a comma then replace it
if (mOutput.back() == ',')
{
mOutput.back() = '}';
}
// Append the object-end character
else
{
mOutput.push_back('}');
}
// Move the comma after the closing character
mOutput.push_back(',');
// Go back one level
Retreat();
// Allow chaining
return *this;
}
// ------------------------------------------------------------------------------------------------
CtxJSON & CtxJSON::ReopenObject()
{
// If the last character is a comma then remove it
if (mOutput.back() == ',')
{
mOutput.pop_back();
}
// If the last character is the object-end character then replace it with a comma
if (mOutput.back() == '}')
{
mOutput.back() = ',';
}
// Allow chaining
return *this;
}
// ------------------------------------------------------------------------------------------------
CtxJSON & CtxJSON::MakeKey()
{
// If the last character is a comma then replace it
if (mOutput.back() == ',')
{
mOutput.back() = ':';
}
// Append the array-end character
else
{
mOutput.push_back(':');
}
// Allow the hook to react
if (mKeyHook)
{
mKeyHook(*this);
}
// Allow chaining
return *this;
}
// ------------------------------------------------------------------------------------------------
bool CtxJSON::CheckWeakRefWrap(HSQUIRRELVM vm, SQInteger idx) noexcept
{
SQRESULT r = sq_getweakrefval(vm, idx);
// Whether the type doesn't have to be wrapped
bool w = true;
// Attempt to grab the value pointed by the weak reference
if (SQ_SUCCEEDED(r))
{
// Attempt to serialize the actual value
w = sq_gettype(vm, -1) != OT_TABLE && sq_gettype(vm, -1) != OT_ARRAY && sq_gettype(vm, -1) == OT_INSTANCE;
// Pop the referenced value
sq_poptop(vm);
}
// Wrap the value by default
return w;
}
// ------------------------------------------------------------------------------------------------
SQRESULT CtxJSON::SerializeParams(HSQUIRRELVM vm)
{
bool wrap_everything_in_array = false;
// Clear the output buffer if necessary
mOutput.clear();
mDepth = 0;
// Fetch the number of objects on the stack
const auto top = sq_gettop(vm);
// If there's more than one argument then they all get wrapped inside an array
// If there is one argument and is not an array, table or instance then do the same
if (top > 2 || (sq_gettype(vm, 2) != OT_TABLE &&
sq_gettype(vm, 2) != OT_ARRAY &&
sq_gettype(vm, 2) != OT_INSTANCE &&
CheckWeakRefWrap(vm, 2)))
{
wrap_everything_in_array = true;
// Open an array
OpenArray();
}
// Serialize every specified argument
for (SQInteger i = 2; i <= top; ++i)
{
if (SQRESULT r = SerializeAt(vm, i); SQ_FAILED(r))
{
return r; // Propagate the error
}
}
// Was everything wrapped inside an array?
if (wrap_everything_in_array)
{
CloseArray();
}
// Remove trailing separator, if any
if (mOutput.back() == ',')
{
mOutput.pop_back();
}
// Push the output string on the stack
sq_pushstring(vm, mOutput.c_str(), static_cast< SQInteger >(mOutput.size()));
// Specify that we have a value on the stack
return 1;
}
// ------------------------------------------------------------------------------------------------
SQRESULT CtxJSON::SerializeAt(HSQUIRRELVM vm, SQInteger idx) // NOLINT(misc-no-recursion)
{
// Identify object type
switch (sq_gettype(vm, idx))
{
case OT_NULL: {
PushNull();
} break;
case OT_INTEGER: {
SQInteger v;
// Attempt to retrieve the value from the stack
if (SQRESULT r = sq_getinteger(vm, idx, &v); SQ_FAILED(r))
{
return r; // Propagate the error
}
// Write the value in the output
PushInteger(v);
} break;
case OT_FLOAT: {
SQFloat v;
// Attempt to retrieve the value from the stack
if (SQRESULT r = sq_getfloat(vm, idx, &v); SQ_FAILED(r))
{
return r; // Propagate the error
}
// Write the value in the output
#ifdef SQUSEDOUBLE
PushDouble(v);
#else
PushFloat(v);
#endif
} break;
case OT_BOOL: {
SQBool v;
// Attempt to retrieve the value from the stack
if (SQRESULT r = sq_getbool(vm, idx, &v); SQ_FAILED(r))
{
return r; // Propagate the error
}
// Write the value in the output
PushBool(v != SQFalse);
} break;
case OT_STRING: {
const SQChar * v = nullptr;
SQInteger n = 0;
// Attempt to retrieve and convert the string
if (SQRESULT r = sq_getstringandsize(vm, idx, &v, &n); SQ_FAILED(r))
{
return r; // Propagate the error
}
// Write the value in the output
PushString(v, static_cast< size_t >(n));
} break;
case OT_TABLE: {
if (SQRESULT r = SerializeTable(vm, idx); SQ_FAILED(r))
{
return r; // Propagate the error
}
} break;
case OT_ARRAY: {
if (SQRESULT r = SerializeArray(vm, idx); SQ_FAILED(r))
{
return r; // Propagate the error
}
} break;
case OT_INSTANCE: {
if (SQRESULT r = SerializeInstance(vm, idx); SQ_FAILED(r))
{
return r; // Propagate the error
}
} break;
case OT_WEAKREF: {
if (SQRESULT r = SerializeWeakRef(vm, idx); SQ_FAILED(r))
{
return r; // Propagate the error
}
} break;
case OT_USERDATA:
case OT_CLOSURE:
case OT_NATIVECLOSURE:
case OT_GENERATOR:
case OT_USERPOINTER:
case OT_THREAD:
case OT_FUNCPROTO:
case OT_CLASS:
case OT_OUTER:
return sq_throwerrorf(vm, _SC("Type (%s) is not serializable"), SqTypeName(sq_gettype(vm, 2)));
}
// Serialization was successful
return SQ_OK;
}
// ------------------------------------------------------------------------------------------------
SQRESULT CtxJSON::SerializeArray(HSQUIRRELVM vm, SQInteger idx) // NOLINT(misc-no-recursion)
{
// Begin array scope
OpenArray();
// Push null to initiate iteration
sq_pushnull(vm);
// So we can use absolute stack indexes to avoid errors
const auto top = sq_gettop(vm);
// Start iterating the array at the specified position in the stack
for(SQRESULT r = SQ_OK; SQ_SUCCEEDED(sq_next(vm, idx));)
{
// Attempt serialization of the currently iterated value
r = SerializeAt(vm, top + 2);
// Check for failures
if (SQ_FAILED(r))
{
// Pop the null iterator, key and value from the stack
sq_pop(vm, 3);
// Propagate the error
return r;
}
// Pop the key and value from the stack (i.e. cleanup after `sq_next`)
sq_pop(vm, 2);
}
// Pop the null iterator
sq_poptop(vm);
// Close array scope
CloseArray();
// Serialization was successful
return SQ_OK;
}
// ------------------------------------------------------------------------------------------------
SQRESULT CtxJSON::SerializeTable(HSQUIRRELVM vm, SQInteger idx) // NOLINT(misc-no-recursion)
{
// Begin object scope
OpenObject();
// Push null to initiate iteration
sq_pushnull(vm);
// So we can use absolute stack indexes to avoid errors
const auto top = sq_gettop(vm);
// Start iterating the object at the specified position in the stack
for(SQRESULT r = SQ_OK; SQ_SUCCEEDED(sq_next(vm, idx));)
{
if (sq_gettype(vm, -2) == OT_STRING)
{
// Attempt serialization of the currently iterated element key
r = SerializeAt(vm, top + 1);
// Can we proceed with the value?
if (SQ_SUCCEEDED(r))
{
// Mark the value above as the key of this element and
// attempt serialization of the currently iterated element value
r = MakeKey().SerializeAt(vm, top + 2);
}
}
else
{
r = sq_throwerror(vm, _SC("Only string values are accepted as object keys"));
}
// Check for failures
if (SQ_FAILED(r))
{
// Pop the null iterator, key and value from the stack
sq_pop(vm, 3);
// Propagate the error
return r;
}
// Pop the key and value from the stack (i.e. cleanup after `sq_next`)
sq_pop(vm, 2);
}
// Pop the null iterator
sq_poptop(vm);
// Close object scope
CloseObject();
// Serialization was successful
return SQ_OK;
}
// ------------------------------------------------------------------------------------------------
SQRESULT CtxJSON::SerializeInstance(HSQUIRRELVM vm, SQInteger idx)
{
sq_pushstring(vm, mMetaMethod.c_str(), static_cast< SQInteger >(mMetaMethod.size()));
// Attempt to retrieve the meta-method from the instance
if(SQRESULT r = sq_get(vm, idx); SQ_FAILED(r))
{
return r; // Propagate the error
}
// Make sure this is actually a closure/function that we can invoke
else if (const auto t = sq_gettype(vm, -1); t != OT_CLOSURE && t != OT_NATIVECLOSURE)
{
// Remove whatever is on the stack
sq_poptop(vm);
// Abort the operation as we can't do anything about it
return sq_throwerrorf(vm, _SC("`_tojson` meta-method is not a closure for type (%s)"), SqTypeName(vm, idx).c_str());
}
// Push the instance itself the stack (the environment)
sq_push(vm, idx);
// Push this instance on the stack (the json context)
ClassType< CtxJSON >::PushInstance(vm, this);
// Invoke the function to perform the conversion in this context
SQRESULT r = sq_call(vm, 2, SQFalse, SQFalse);
// Remove the closure from the stack
sq_poptop(vm);
// Propagate the result, whatever that is
return r;
}
// ------------------------------------------------------------------------------------------------
SQRESULT CtxJSON::SerializeWeakRef(HSQUIRRELVM vm, SQInteger idx) // NOLINT(misc-no-recursion)
{
SQRESULT r = sq_getweakrefval(vm, idx);
// Attempt to grab the value pointed by the weak reference
if (SQ_SUCCEEDED(r))
{
// Attempt to serialize the actual value
r = SerializeAt(vm, sq_gettop(vm));
// Pop the referenced value
sq_poptop(vm);
}
// Propagate the error, if any
return r;
}
// ------------------------------------------------------------------------------------------------
SQRESULT CtxJSON::PushValues(HSQUIRRELVM vm)
{
// Fetch the number of objects on the stack
const auto top = sq_gettop(vm);
// Do we have a value?
if (top < 2)
{
return sq_throwerror(vm, _SC("Must specify at least one value to be pushed"));
}
// Serialize every specified argument
for (SQInteger i = 2; i <= top; ++i)
{
if (SQRESULT r = SerializeAt(vm, i); SQ_FAILED(r))
{
return r; // Propagate the error
}
}
// Allow chaining
sq_push(vm, 1);
// Specify that a value was returned
return 1;
}
// ------------------------------------------------------------------------------------------------
SQRESULT CtxJSON::PushElement(HSQUIRRELVM vm)
{
// Fetch the number of objects on the stack
const auto top = sq_gettop(vm);
// Do we have a value?
if (top < 3)
{
return sq_throwerrorf(vm, _SC("Not enough parameters. Received %lld but %lld needed"), top-1, 2);
}
else if (sq_gettype(vm, 2) != OT_STRING)
{
return sq_throwerrorf(vm, _SC("Element key must be a string"));
}
// Attempt serialization of the currently iterated element key
if (SQRESULT r = SerializeAt(vm, 2); SQ_SUCCEEDED(r))
{
// Mark the value above as the key of this element and
// attempt serialization of the currently iterated element value
r = MakeKey().SerializeAt(vm, 3);
// Check for failures
if (SQ_FAILED(r))
{
return r; // Propagate the error
}
}
// Allow chaining
sq_push(vm, 1);
// Specify that a value was returned
return 1;
}
// ------------------------------------------------------------------------------------------------
CtxJSON & CtxJSON::PushKey(StackStrF & key)
{
// Validate the string value
if (key.mLen >= 0 && SQ_SUCCEEDED(key.mRes))
{
PushString(key.mPtr, static_cast< size_t >(key.mLen));
MakeKey();
}
else
{
STHROWF("Invalid object key");
}
// Allow chaining
return *this;
}
// ------------------------------------------------------------------------------------------------
void CtxJSON::PushNull()
{
mOutput.append("null,");
}
// ------------------------------------------------------------------------------------------------
void CtxJSON::PushInteger(SQInteger value)
{
fmt::format_int f(value);
// Append the formatted integer to the buffer
mOutput.append(f.data(), f.size());
mOutput.push_back(',');
}
// ------------------------------------------------------------------------------------------------
void CtxJSON::PushFloat(float value)
{
fmt::format_to(std::back_inserter(mOutput), "{},", value);
}
// ------------------------------------------------------------------------------------------------
void CtxJSON::PushDouble(double value)
{
fmt::format_to(std::back_inserter(mOutput), "{},", value);
}
// ------------------------------------------------------------------------------------------------
void CtxJSON::PushBool(bool value)
{
if (value)
{
mOutput.append("true,", 5);
}
else
{
mOutput.append("false,", 6);
}
}
// ------------------------------------------------------------------------------------------------
void CtxJSON::PushString(const SQChar * str)
{
mOutput.push_back('"');
mOutput.append(str);
mOutput.push_back('"');
mOutput.push_back(',');
// Allow the hook to know
mString.assign(str);
}
// ------------------------------------------------------------------------------------------------
void CtxJSON::PushString(const SQChar * str, size_t length)
{
mOutput.push_back('"');
mOutput.append(str, length);
mOutput.push_back('"');
mOutput.push_back(',');
// Allow the hook to know
mString.assign(str, length);
}
// ------------------------------------------------------------------------------------------------
static SQInteger SqToJSON(HSQUIRRELVM vm) noexcept
{
// Make sure the instance is cleaned up even in the case of exceptions
DeleteGuard< CtxJSON > sq_dg(new CtxJSON());
// Remember the instance, so we don't have to cast the script object back
auto ctx = sq_dg.Get();
// Turn it into a script object because it may be passed as a parameter to `_tojson` meta-methods
LightObj obj(sq_dg, vm);
// Proceed with the serialization
return ctx->SerializeParams(vm);
}
// ------------------------------------------------------------------------------------------------
static SQInteger SqToCompactJSON(HSQUIRRELVM vm) noexcept
{
// Make sure the instance is cleaned up even in the case of exceptions
DeleteGuard< CtxJSON > sq_dg(new CtxJSON(false));
// Remember the instance, so we don't have to cast the script object back
auto ctx = sq_dg.Get();
// Turn it into a script object because it may be passed as a parameter to `_tojson` meta-methods
LightObj obj(sq_dg, vm);
// Proceed with the serialization
return ctx->SerializeParams(vm);
}
// ================================================================================================
void Register_JSON(HSQUIRRELVM vm)
{
RootTable(vm).SquirrelFunc(_SC("SqToJSON"), SqToJSON);
RootTable(vm).SquirrelFunc(_SC("SqToCompactJSON"), SqToCompactJSON);
RootTable(vm).SquirrelFunc(_SC("SqFromJSON"), SqFromJSON);
// --------------------------------------------------------------------------------------------
RootTable(vm).Bind(_SC("SqCtxJSON"),
Class< CtxJSON, NoCopy< CtxJSON > >(vm, SqCtxJSON::Str)
// Constructors
.Ctor()
.Ctor< bool >()
.Ctor< bool, StackStrF & >()
// Meta-methods
.SquirrelFunc(_SC("_typename"), &SqCtxJSON::Fn)
// Properties
.Prop(_SC("Output"), &CtxJSON::GetOutput)
.Prop(_SC("Depth"), &CtxJSON::GetDepth)
.Prop(_SC("OOA"), &CtxJSON::GetObjectOverArray, &CtxJSON::SetObjectOverArray)
.Prop(_SC("ObjectOverArray"), &CtxJSON::GetObjectOverArray, &CtxJSON::SetObjectOverArray)
// Member Methods
.SquirrelMethod< CtxJSON, &CtxJSON::SerializeParams >(_SC("Serialize"))
.SquirrelMethod< CtxJSON, &CtxJSON::PushValues >(_SC("PushValues"))
.SquirrelMethod< CtxJSON, &CtxJSON::PushElement >(_SC("PushElement"))
.Func(_SC("OpenArray"), &CtxJSON::OpenArray)
.Func(_SC("CloseArray"), &CtxJSON::CloseArray)
.Func(_SC("OpenObject"), &CtxJSON::OpenObject)
.Func(_SC("CloseObject"), &CtxJSON::CloseObject)
.Func(_SC("MakeKey"), &CtxJSON::MakeKey)
.FmtFunc(_SC("PushKey"), &CtxJSON::PushKey)
.Func(_SC("SetOOA"), &CtxJSON::SetObjectOverArray)
.Func(_SC("SetObjectOverArray"), &CtxJSON::SetObjectOverArray)
);
}
} // Namespace:: SqMod

View File

@ -5,12 +5,281 @@
#include "Library/IO/Buffer.hpp"
// ------------------------------------------------------------------------------------------------
#include <sajson.h>
#include <functional>
// ------------------------------------------------------------------------------------------------
#include <fmt/args.h>
#include <fmt/format.h>
#include <fmt/xchar.h>
// ------------------------------------------------------------------------------------------------
namespace SqMod {
// ------------------------------------------------------------------------------------------------
/* ------------------------------------------------------------------------------------------------
* JSON serializer. The generated JSON output is always minified for efficiency reasons.
*/
struct CtxJSON
{
/* --------------------------------------------------------------------------------------------
* Output string.
*/
String mOutput{};
/* --------------------------------------------------------------------------------------------
* Prefer a table with named members even when a simple array would do the job.
* Take a Vector3 for example. Compact array [x, y, z] or named object {x: #.#, y: #.#, z: #.#}
*/
bool mObjectOverArray{true};
/* --------------------------------------------------------------------------------------------
* How nested are we currently.
*/
uint32_t mDepth{0};
/* --------------------------------------------------------------------------------------------
* The meta-method name to use on objects.
*/
String mMetaMethod{"_tojson"};
/* --------------------------------------------------------------------------------------------
* Last pushed string value. Can be used to heck for key name in the hook.
*/
String mString{};
/* --------------------------------------------------------------------------------------------
* Internal utility used to monitor the existence of certain keys to allow overloading.
*/
std::function< void(CtxJSON&) > mKeyHook{};
/* --------------------------------------------------------------------------------------------
* Default constructor.
*/
CtxJSON() = default;
/* --------------------------------------------------------------------------------------------
* Explicit constructor.
*/
explicit CtxJSON(bool ooa)
: CtxJSON()
{
mObjectOverArray = ooa;
}
/* --------------------------------------------------------------------------------------------
* Explicit constructor.
*/
CtxJSON(bool ooa, StackStrF & mmname)
: CtxJSON()
{
mObjectOverArray = ooa;
// Allow custom metamethod names
mMetaMethod.assign(mmname.mPtr, static_cast< size_t >(mmname.mLen));
}
/* --------------------------------------------------------------------------------------------
* Internal constructor.
*/
explicit CtxJSON(std::function< void(CtxJSON&) > && kh)
: CtxJSON()
{
mKeyHook = std::move(kh);
}
/* --------------------------------------------------------------------------------------------
* Copy constructor.
*/
CtxJSON(const CtxJSON &) = default;
/* --------------------------------------------------------------------------------------------
* Move constructor.
*/
CtxJSON(CtxJSON &&) noexcept = default;
/* --------------------------------------------------------------------------------------------
* Destructor.
*/
~CtxJSON() = default;
/* --------------------------------------------------------------------------------------------
* Copy assignment operator.
*/
CtxJSON & operator = (const CtxJSON &) = default;
/* --------------------------------------------------------------------------------------------
* Move assignment operator.
*/
CtxJSON & operator = (CtxJSON &&) noexcept = default;
/* --------------------------------------------------------------------------------------------
* Retrieve the current depth.
*/
SQMOD_NODISCARD const String & GetOutput() const noexcept
{
return mOutput;
}
/* --------------------------------------------------------------------------------------------
* Retrieve the current depth.
*/
SQMOD_NODISCARD SQInteger GetDepth() const noexcept
{
return mDepth;
}
/* --------------------------------------------------------------------------------------------
* Retrieve whether objects are preferred over arrays.
*/
SQMOD_NODISCARD bool GetObjectOverArray() const noexcept
{
return mObjectOverArray;
}
/* --------------------------------------------------------------------------------------------
* Retrieve whether objects are preferred over arrays.
*/
CtxJSON & SetObjectOverArray(bool toggle) noexcept
{
mObjectOverArray = toggle;
// Allow chaining
return *this;
}
/* --------------------------------------------------------------------------------------------
* Increase indentation by one level.
*/
void Advance() noexcept
{
++mDepth;
}
/* --------------------------------------------------------------------------------------------
* Decrease indentation by one level.
*/
void Retreat() noexcept
{
assert(mDepth > 0);
if (mDepth) --mDepth;
}
/* --------------------------------------------------------------------------------------------
* Begin writing an array.
*/
CtxJSON & OpenArray();
/* --------------------------------------------------------------------------------------------
* Stop writing an array.
*/
CtxJSON & CloseArray();
/* --------------------------------------------------------------------------------------------
* Resume writing an array.
*/
CtxJSON & ReopenArray();
/* --------------------------------------------------------------------------------------------
* Begin writing an object.
*/
CtxJSON & OpenObject();
/* --------------------------------------------------------------------------------------------
* Stop writing an object.
*/
CtxJSON & CloseObject();
/* --------------------------------------------------------------------------------------------
* Resume writing an object.
*/
CtxJSON & ReopenObject();
/* --------------------------------------------------------------------------------------------
* Begin writing a key value.
*/
CtxJSON & MakeKey();
/* --------------------------------------------------------------------------------------------
* Check whether the specified weak-ref points to a type of value that must be wrapped.
*/
SQMOD_NODISCARD static bool CheckWeakRefWrap(HSQUIRRELVM vm, SQInteger idx) noexcept;
/* --------------------------------------------------------------------------------------------
* Serialize given arguments.
*/
SQRESULT SerializeParams(HSQUIRRELVM vm);
/* --------------------------------------------------------------------------------------------
* Serialize the value a specific position in the stack.
*/
SQRESULT SerializeAt(HSQUIRRELVM vm, SQInteger idx);
/* --------------------------------------------------------------------------------------------
* Serialize the array a specific position in the stack. Stack index must be absolute!
*/
SQRESULT SerializeArray(HSQUIRRELVM vm, SQInteger idx);
/* --------------------------------------------------------------------------------------------
* Serialize the table a specific position in the stack. Stack index must be absolute!
*/
SQRESULT SerializeTable(HSQUIRRELVM vm, SQInteger idx);
/* --------------------------------------------------------------------------------------------
* Serialize the instance a specific position in the stack. Stack index must be absolute!
*/
SQRESULT SerializeInstance(HSQUIRRELVM vm, SQInteger idx);
/* --------------------------------------------------------------------------------------------
* Serialize the weak-ref a specific position in the stack. Stack index must be absolute!
*/
SQRESULT SerializeWeakRef(HSQUIRRELVM vm, SQInteger idx);
/* --------------------------------------------------------------------------------------------
* Serialize a value to the current container. It assumes an array or object is currently open.
*/
SQRESULT PushValues(HSQUIRRELVM vm);
/* --------------------------------------------------------------------------------------------
* Serialize a key/value pair to the current object. It assumes an object is currently open.
*/
SQRESULT PushElement(HSQUIRRELVM vm);
/* --------------------------------------------------------------------------------------------
* Push a key in the output. It assumes an object was open and previous element closed properly.
*/
CtxJSON & PushKey(StackStrF & key);
/* --------------------------------------------------------------------------------------------
* Write a null value to the output.
*/
void PushNull();
/* --------------------------------------------------------------------------------------------
* Write an integer value to the output.
*/
void PushInteger(SQInteger value);
/* --------------------------------------------------------------------------------------------
* Write a single precision floating point value to the output.
*/
void PushFloat(float value);
/* --------------------------------------------------------------------------------------------
* Write a double precision floating point value to the output.
*/
void PushDouble(double value);
/* --------------------------------------------------------------------------------------------
* Write a boolean value to the output.
*/
void PushBool(bool value);
/* --------------------------------------------------------------------------------------------
* Write a string value to the output.
*/
void PushString(const SQChar * str);
/* --------------------------------------------------------------------------------------------
* Write a string value to the output.
*/
void PushString(const SQChar * str, size_t length);
};
} // Namespace:: SqMod

View File

@ -55,40 +55,60 @@ SQMOD_DECL_TYPENAME(CVehicleTn, _SC("CVehicle"))
/* ------------------------------------------------------------------------------------------------
* Used to fetch the legacy entity instance even if a native one was specified.
*/
template < class T, class U > inline T & GetLgEnt(LightObj & o)
template < class LEGACY, class NATIVE > inline LEGACY & GetLgEnt(LightObj & o)
{
auto type = static_cast< AbstractStaticClassData * >(o.GetTypeTag());
const auto type = static_cast< AbstractStaticClassData * >(o.GetTypeTag());
// Legacy entity type?
if (type == StaticClassTypeTag< T >::Get())
if (type == StaticClassTypeTag< LEGACY >::Get())
{
return *o.CastI< T >();
return *o.CastI< LEGACY >();
}
// Native entity type?
if (type == StaticClassTypeTag< U >::Get())
if (type == StaticClassTypeTag< NATIVE >::Get())
{
return *EntityInstSelect< U >(o.CastI< U >()->GetID()).mLgInst;
return *EntityInstSelect< NATIVE >::Get(o.CastI< NATIVE >()->GetID()).mLgInst;
}
STHROWF("Invalid entity type");
STHROWF("Invalid entity type: {}", SqTypeName(SqVM(), o));
SQ_UNREACHABLE
}
/* ------------------------------------------------------------------------------------------------
* Used to fetch the native entity instance even if a legacy one was specified.
*/
template < class LEGACY, class NATIVE > inline NATIVE & GetNativeEnt(LightObj & o)
{
const auto type = static_cast< AbstractStaticClassData * >(o.GetTypeTag());
// Legacy entity type?
if (type == StaticClassTypeTag< LEGACY >::Get())
{
return o.CastI< LEGACY >()->Get();
}
// Native entity type?
if (type == StaticClassTypeTag< NATIVE >::Get())
{
return *EntityInstSelect< NATIVE >::Get(o.CastI< NATIVE >()->GetID()).mInst;
}
STHROWF("Invalid entity type: {}", SqTypeName(SqVM(), o));
SQ_UNREACHABLE
}
/* ------------------------------------------------------------------------------------------------
* Used to fetch the legacy entity identifier even if a native one was specified.
*/
template < class T, class U > SQMOD_NODISCARD inline int32_t GetLgEntID(LightObj & o)
template < class LEGACY, class NATIVE > SQMOD_NODISCARD inline int32_t GetLgEntID(LightObj & o)
{
auto type = static_cast< AbstractStaticClassData * >(o.GetTypeTag());
const auto type = static_cast< AbstractStaticClassData * >(o.GetTypeTag());
// Legacy entity type?
if (type == StaticClassTypeTag< T >::Get())
if (type == StaticClassTypeTag< LEGACY >::Get())
{
return o.CastI< T >()->mID;
return o.CastI< LEGACY >()->mID;
}
// Native entity type?
if (type == StaticClassTypeTag< U >::Get())
if (type == StaticClassTypeTag< NATIVE >::Get())
{
return o.CastI< U >()->GetID();
return o.CastI< NATIVE >()->GetID();
}
STHROWF("Invalid entity type");
STHROWF("Invalid entity type: {}", SqTypeName(SqVM(), o));
SQ_UNREACHABLE
}
@ -478,14 +498,14 @@ struct LgCheckpoint
SQMOD_NODISCARD int GetWorld() const { return Get().GetWorld(); }
SQMOD_NODISCARD LgARGB GetColor() const { const Color4 c = Get().GetColor(); return LgARGB{c.a, c.r, c.g, c.b}; }
SQMOD_NODISCARD LgEntityVector GetPos() const
{ return LgEntityVector(mID, LgEntityType::Checkpoint, 0, Get().GetPosition()); }
{ return {mID, LgEntityType::Checkpoint, 0, Get().GetPosition()}; }
SQMOD_NODISCARD float GetRadius() const { return Get().GetRadius(); }
SQMOD_NODISCARD int GetID() const { return mID; }
SQMOD_NODISCARD LgPlayer * GetOwner() const
{ const int id = Get().GetOwnerID(); return VALID_ENTITYEX(id, SQMOD_PLAYER_POOL) ? Core::Get().GetPlayer(id).mLgInst : nullptr; }
// --------------------------------------------------------------------------------------------
void Delete() const { _Func->DeleteCheckPoint(GetIdentifier()); }
SQMOD_NODISCARD bool StreamedToPlayer(LgPlayer & player) const;
SQMOD_NODISCARD bool StreamedToPlayer(LightObj & player) const;
};
/* ------------------------------------------------------------------------------------------------
@ -546,11 +566,11 @@ struct LgObject
SQMOD_NODISCARD int GetAlpha() const { return Get().GetAlpha(); }
SQMOD_NODISCARD int GetWorld() const { return Get().GetWorld(); }
SQMOD_NODISCARD LgEntityVector GetPos() const
{ return LgEntityVector(mID, LgEntityType::Object, LgObjectVectorFlag::Pos, Get().GetPosition()); }
{ return {mID, LgEntityType::Object, LgObjectVectorFlag::Pos, Get().GetPosition()}; }
SQMOD_NODISCARD LgEntityQuaternion GetRotation() const
{ return LgEntityQuaternion(mID, LgEntityType::Object, 0, Get().GetRotation()); }
{ return {mID, LgEntityType::Object, 0, Get().GetRotation()}; }
SQMOD_NODISCARD LgEntityVector GetRotationEuler() const
{ return LgEntityVector(mID, LgEntityType::Object, LgObjectVectorFlag::Rotation, Get().GetRotationEuler()); }
{ return {mID, LgEntityType::Object, LgObjectVectorFlag::Rotation, Get().GetRotationEuler()}; }
SQMOD_NODISCARD int GetID() const { return mID; }
SQMOD_NODISCARD bool GetReportingShots() const { return Get().GetShotReport(); }
SQMOD_NODISCARD bool GetReportingBumps() const { return Get().GetTouchedReport(); }
@ -563,7 +583,7 @@ struct LgObject
void RotateToEuler(const Vector3 & rotation, int time) const { Get().RotateToEuler(rotation, static_cast< uint32_t >(time)); }
void RotateByEuler(const Vector3 & rotOffset, int time) const { Get().RotateByEuler(rotOffset, static_cast< uint32_t >(time)); }
void SetAlpha(int alpha, int fadeTime) const { Get().SetAlphaEx(alpha, static_cast< uint32_t >(fadeTime)); }
SQMOD_NODISCARD bool StreamedToPlayer(LgPlayer & player) const;
SQMOD_NODISCARD bool StreamedToPlayer(LightObj & player) const;
};
/* ------------------------------------------------------------------------------------------------
@ -627,7 +647,7 @@ struct LgPickup
SQMOD_NODISCARD bool GetAuto() const { return Get().GetAutomatic(); }
SQMOD_NODISCARD int GetAutoTimer() const { return Get().GetAutoTimer(); }
SQMOD_NODISCARD LgEntityVector GetPos() const
{ return LgEntityVector(mID, LgEntityType::Pickup, 0, Get().GetPosition()); }
{ return {mID, LgEntityType::Pickup, 0, Get().GetPosition()}; }
SQMOD_NODISCARD int GetModel() const { return Get().GetModel(); }
SQMOD_NODISCARD int GetQuantity() const { return Get().GetQuantity(); }
SQMOD_NODISCARD int GetID() const { return mID; }
@ -635,7 +655,7 @@ struct LgPickup
// --------------------------------------------------------------------------------------------
void Delete() const { _Func->DeletePickup(GetIdentifier()); }
void Respawn() const { Get().Refresh(); }
SQMOD_NODISCARD bool StreamedToPlayer(LgPlayer & player) const;
SQMOD_NODISCARD bool StreamedToPlayer(LightObj & player) const;
};
/* ------------------------------------------------------------------------------------------------
@ -703,7 +723,7 @@ struct LgPlayer
void SetScore(int score) const { Get().SetScore(score); }
void SetImmunity(uint32_t immunity) const { Get().SetImmunity(immunity); }
void SetHeading(float heading) const { Get().SetHeading(heading); }
void SetVehicle(LgVehicle & vehicle) const;
void SetVehicle(LightObj & vehicle) const;
void SetFrozen(bool toggle) const { _Func->SetPlayerOption(GetIdentifier(), vcmpPlayerOptionControllable, static_cast< uint8_t >(!toggle)); }
void SetDriveByEnabled(bool toggle) const { _Func->SetPlayerOption(GetIdentifier(), vcmpPlayerOptionDriveBy, static_cast< uint8_t >(toggle)); }
void SetWhiteScanLines(bool toggle) const { _Func->SetPlayerOption(GetIdentifier(), vcmpPlayerOptionWhiteScanlines, static_cast< uint8_t >(toggle)); }
@ -720,7 +740,7 @@ struct LgPlayer
void SetWantedLevel(int level) const { Get().SetWantedLevel(level); }
// --------------------------------------------------------------------------------------------
SQMOD_NODISCARD LgEntityVector GetPosition() const
{ return LgEntityVector(mID, LgEntityType::Player, LgPlayerVectorFlag::Pos, Get().GetPosition()); }
{ return {mID, LgEntityType::Player, LgPlayerVectorFlag::Pos, Get().GetPosition()}; }
SQMOD_NODISCARD int GetClass() const { return Get().GetClass(); }
SQMOD_NODISCARD bool GetAdmin() const { return Get().GetAdmin(); }
SQMOD_NODISCARD const SQChar * GetIP() const { return Get().GetIP(); }
@ -732,7 +752,7 @@ struct LgPlayer
SQMOD_NODISCARD const SQChar * GetName() const { return Get().GetName(); }
SQMOD_NODISCARD int GetTeam() const { return Get().GetTeam(); }
SQMOD_NODISCARD int GetSkin() const { return Get().GetSkin(); }
SQMOD_NODISCARD LgEntityRGB GetColour() const { return LgEntityRGB(mID, LgEntityType::Player, 0, Get().GetColor()); }
SQMOD_NODISCARD LgEntityRGB GetColour() const { return {mID, LgEntityType::Player, 0, Get().GetColor()}; }
SQMOD_NODISCARD int GetMoney() const { return Get().GetMoney(); }
SQMOD_NODISCARD int GetScore() const { return Get().GetScore(); }
SQMOD_NODISCARD int GetPing() const { return Get().GetPing(); }
@ -764,7 +784,7 @@ struct LgPlayer
SQMOD_NODISCARD LgPlayer * GetSpectateTarget() const
{ const int id = _Func->GetPlayerSpectateTarget(GetIdentifier()); return VALID_ENTITYEX(id, SQMOD_PLAYER_POOL) ? Core::Get().GetPlayer(id).mLgInst : nullptr; }
SQMOD_NODISCARD LgEntityVector GetSpeed() const
{ return LgEntityVector(mID, LgEntityType::Player, LgPlayerVectorFlag::Speed, Get().GetSpeed()); }
{ return {mID, LgEntityType::Player, LgPlayerVectorFlag::Speed, Get().GetSpeed()}; }
SQMOD_NODISCARD bool GetCanUseColors() const { return _Func->GetPlayerOption(GetIdentifier(), vcmpPlayerOptionChatTagsEnabled) >= 1; }
SQMOD_NODISCARD bool GetMarkerVisible() const { return _Func->GetPlayerOption(GetIdentifier(), vcmpPlayerOptionHasMarker) >= 1; }
SQMOD_NODISCARD bool GetDrunkStatus() const { return _Func->GetPlayerOption(GetIdentifier(), vcmpPlayerOptionDrunkEffects) >= 1; }
@ -801,8 +821,8 @@ struct LgPlayer
SQMOD_NODISCARD int GetWeaponAtSlot(int slot) const { return Get().GetWeaponAtSlot(slot); }
SQMOD_NODISCARD int GetAmmoAtSlot(int slot) const { return Get().GetAmmoAtSlot(slot); }
void SetAlpha(int alpha, int fadeTime) const { Get().SetAlphaEx(alpha, fadeTime); }
SQMOD_NODISCARD bool StreamedToPlayer(const LgPlayer & player) const { return Get().IsStreamedFor(player.Get()); }
void SetVehicleSlot(const LgVehicle & vehicle, int slot) const;
SQMOD_NODISCARD bool StreamedToPlayer(LightObj & player) const { return Get().IsStreamedFor(GetNativeEnt< LgPlayer, CPlayer >(player)); }
void SetVehicleSlot(LightObj & vehicle, int slot) const;
void Select() const { Get().ForceSelect(); }
void RestoreCamera() const { Get().RestoreCamera(); }
void RemoveMarker() const { _Func->SetPlayerOption(GetIdentifier(), vcmpPlayerOptionHasMarker, 0); }
@ -915,13 +935,13 @@ struct LgVehicle
SQMOD_NODISCARD int GetModel() const { return Get().GetModel(); }
SQMOD_NODISCARD uint32_t GetImmunity() const { return Get().GetImmunity(); }
SQMOD_NODISCARD LgEntityVector GetPosition() const
{ return LgEntityVector(mID, LgEntityType::Vehicle, LgVehicleVectorFlag::Pos, Get().GetPosition()); }
{ return {mID, LgEntityType::Vehicle, LgVehicleVectorFlag::Pos, Get().GetPosition()}; }
SQMOD_NODISCARD LgEntityVector GetSpawnPos() const
{ return LgEntityVector(mID, LgEntityType::Vehicle, LgVehicleVectorFlag::SpawnPos, Get().GetSpawnPosition()); }
{ return {mID, LgEntityType::Vehicle, LgVehicleVectorFlag::SpawnPos, Get().GetSpawnPosition()}; }
SQMOD_NODISCARD LgEntityQuaternion GetSpawnAngle() const
{ return LgEntityQuaternion(mID, LgEntityType::Vehicle, LgVehicleQuaternionFlag::SpawnAngle, Get().GetSpawnRotation()); }
{ return {mID, LgEntityType::Vehicle, LgVehicleQuaternionFlag::SpawnAngle, Get().GetSpawnRotation()}; }
SQMOD_NODISCARD LgEntityVector GetSpawnAngleEuler() const
{ return LgEntityVector(mID, LgEntityType::Vehicle, LgVehicleVectorFlag::SpawnAngle, Get().GetSpawnRotationEuler()); }
{ return {mID, LgEntityType::Vehicle, LgVehicleVectorFlag::SpawnAngle, Get().GetSpawnRotationEuler()}; }
SQMOD_NODISCARD uint32_t GetIdleRespawnTimer() const { return Get().GetIdleRespawnTimer(); }
SQMOD_NODISCARD float GetHealth() const { return Get().GetHealth(); }
SQMOD_NODISCARD int GetColour1() const { return Get().GetPrimaryColor(); }
@ -939,21 +959,21 @@ struct LgVehicle
SQMOD_NODISCARD int GetSyncType() const { return Get().GetSyncType(); }
SQMOD_NODISCARD bool GetWrecked() const { return Get().IsWrecked(); }
SQMOD_NODISCARD LgEntityQuaternion GetRotation() const
{ return LgEntityQuaternion(mID, LgEntityType::Vehicle, LgVehicleQuaternionFlag::Angle, Get().GetRotation()); }
{ return {mID, LgEntityType::Vehicle, LgVehicleQuaternionFlag::Angle, Get().GetRotation()}; }
SQMOD_NODISCARD LgEntityVector GetEulerRotation() const
{ return LgEntityVector(mID, LgEntityType::Vehicle, LgVehicleVectorFlag::Angle, Get().GetRotationEuler()); }
{ return {mID, LgEntityType::Vehicle, LgVehicleVectorFlag::Angle, Get().GetRotationEuler()}; }
SQMOD_NODISCARD LgEntityVector GetSpeed() const
{ return LgEntityVector(mID, LgEntityType::Vehicle, LgVehicleVectorFlag::Speed, Get().GetSpeed()); }
{ return {mID, LgEntityType::Vehicle, LgVehicleVectorFlag::Speed, Get().GetSpeed()}; }
SQMOD_NODISCARD LgEntityVector GetRelativeSpeed() const
{ return LgEntityVector(mID, LgEntityType::Vehicle, LgVehicleVectorFlag::RelSpeed, Get().GetRelativeSpeed()); }
{ return {mID, LgEntityType::Vehicle, LgVehicleVectorFlag::RelSpeed, Get().GetRelativeSpeed()}; }
SQMOD_NODISCARD LgEntityVector GetTurnSpeed() const
{ return LgEntityVector(mID, LgEntityType::Vehicle, LgVehicleVectorFlag::TurnSpeed, Get().GetTurnSpeed()); }
{ return {mID, LgEntityType::Vehicle, LgVehicleVectorFlag::TurnSpeed, Get().GetTurnSpeed()}; }
SQMOD_NODISCARD LgEntityVector GetRelativeTurnSpeed() const
{ return LgEntityVector(mID, LgEntityType::Vehicle, LgVehicleVectorFlag::RelTurnSpeed, Get().GetRelativeTurnSpeed()); }
{ return {mID, LgEntityType::Vehicle, LgVehicleVectorFlag::RelTurnSpeed, Get().GetRelativeTurnSpeed()}; }
SQMOD_NODISCARD int GetRadio() const { return Get().GetRadio(); }
SQMOD_NODISCARD bool GetRadioLockStatus() const { return _Func->GetVehicleOption(GetIdentifier(), vcmpVehicleOptionRadioLocked) >= 1; }
SQMOD_NODISCARD bool GetGhost() const { return _Func->GetVehicleOption(GetIdentifier(), vcmpVehicleOptionGhost) >= 1; }
SQMOD_NODISCARD LgVector GetTurretRotation() const { const Vector2 v = Get().GetTurretRotation(); return LgVector(v.x, v.y, 0); }
SQMOD_NODISCARD LgVector GetTurretRotation() const { const Vector2 v = Get().GetTurretRotation(); return {v.x, v.y, 0}; }
SQMOD_NODISCARD bool GetSingleUse() const { return _Func->GetVehicleOption(GetIdentifier(), vcmpVehicleOptionSingleUse) >= 1; }
SQMOD_NODISCARD bool GetTaxiLight() const { return (_Func->GetVehicleLightsData(GetIdentifier()) & (1 << 8)) != 0; }
// --------------------------------------------------------------------------------------------
@ -966,7 +986,7 @@ struct LgVehicle
void SetPartStatus(int part, int status) const { Get().SetPartStatus(part, status); }
SQMOD_NODISCARD int GetTyreStatus(int tyre) const { return Get().GetTyreStatus(tyre); }
void SetTyreStatus(int part, int status) const { Get().SetTyreStatus(part, status); }
SQMOD_NODISCARD bool GetStreamedForPlayer(LgPlayer & player) const { return Get().IsStreamedFor(player.Get()); }
SQMOD_NODISCARD bool GetStreamedForPlayer(LightObj & player) const { return Get().IsStreamedFor(GetNativeEnt< LgPlayer, CPlayer >(player)); }
SQMOD_NODISCARD LgPlayer * GetOccupant(int slot) const
{ const int id = _Func->GetVehicleOccupant(GetIdentifier(), slot); return VALID_ENTITYEX(id, SQMOD_PLAYER_POOL) ? Core::Get().GetPlayer(id).mLgInst : nullptr; }
void SetHandlingData(int rule, float value) const { Get().SetHandlingRule(rule, value); }
@ -982,11 +1002,11 @@ struct LgVehicle
};
// ------------------------------------------------------------------------------------------------
inline bool LgCheckpoint::StreamedToPlayer(LgPlayer & player) const { return Get().IsStreamedFor(player.Get()); }
inline bool LgObject::StreamedToPlayer(LgPlayer & player) const { return Get().IsStreamedFor(player.Get()); }
inline bool LgPickup::StreamedToPlayer(LgPlayer & player) const { return Get().IsStreamedFor(player.Get()); }
inline void LgPlayer::SetVehicle(LgVehicle & vehicle) const { Get().Embark(vehicle.Get()); }
inline void LgPlayer::SetVehicleSlot(const LgVehicle & vehicle, int slot) const { Get().EmbarkEx(vehicle.Get(), slot, true, false); }
inline bool LgCheckpoint::StreamedToPlayer(LightObj & player) const { return Get().IsStreamedFor(GetNativeEnt< LgPlayer, CPlayer >(player)); }
inline bool LgObject::StreamedToPlayer(LightObj & player) const { return Get().IsStreamedFor(GetNativeEnt< LgPlayer, CPlayer >(player)); }
inline bool LgPickup::StreamedToPlayer(LightObj & player) const { return Get().IsStreamedFor(GetNativeEnt< LgPlayer, CPlayer >(player)); }
inline void LgPlayer::SetVehicle(LightObj & vehicle) const { Get().Embark(GetNativeEnt< LgVehicle, CVehicle >(vehicle)); }
inline void LgPlayer::SetVehicleSlot(LightObj & vehicle, int slot) const { Get().EmbarkEx(GetNativeEnt< LgVehicle, CVehicle >(vehicle), slot, true, false); }
// ------------------------------------------------------------------------------------------------
void LgCheckpointSetID(LgCheckpoint * inst, int32_t id) { assert(inst); if (inst) inst->mID = id; }
@ -1434,8 +1454,8 @@ static void LgUnbanIP(StackStrF & ip) { _Func->UnbanIP(const_cast< SQChar * >(ip
SQMOD_NODISCARD static bool LgIsIPBanned(StackStrF & ip) { return _Func->IsIPBanned(const_cast< SQChar * >(ip.mPtr)) >= 1; }
// ------------------------------------------------------------------------------------------------
SQMOD_NODISCARD static int LgGetPlayerIDFromName(StackStrF & name) { return _Func->GetPlayerIdFromName(name.mPtr); }
SQMOD_NODISCARD static bool LgIsWorldCompatibleWithPlayer (LgPlayer & player, int world)
{ return _Func->IsPlayerWorldCompatible(player.GetIdentifier(), world) >= 1; }
SQMOD_NODISCARD static bool LgIsWorldCompatibleWithPlayer(LightObj & player, int world)
{ return _Func->IsPlayerWorldCompatible(GetLgEntID< LgPlayer, CPlayer >(player), world) >= 1; }
// ------------------------------------------------------------------------------------------------
static LightObj & LgCreatePickupCompat(int model, const Vector3 & pos)
{ return Core::Get().NewPickup(model, 1, 0, pos.x, pos.y, pos.z, 255, false, SQMOD_CREATE_DEFAULT, NullLightObj()).mLgObj; }
@ -1449,7 +1469,7 @@ static LightObj & LgCreatePickup(int model, int world, int quantity, const Vecto
static LightObj & LgCreateObject(int model, int world, const Vector3 & pos, int alpha)
{ return Core::Get().NewObject(model, world, pos.x, pos.y, pos.z, alpha, SQMOD_CREATE_DEFAULT, NullLightObj()).mLgObj; }
static LightObj & LgCreateCheckpoint(LightObj & player, int world, bool sphere, const Vector3 & pos, const Color4 & col, float radius) {
const int32_t id = player.IsNull() ? -1 : player.CastI< LgPlayer >()->GetIdentifier();
const int32_t id = player.IsNull() ? -1 : GetLgEntID< LgPlayer, CPlayer >(player);
return Core::Get().NewCheckpoint(id, world, sphere, pos.x, pos.y, pos.z, col.r, col.g, col.b, col.a, radius, SQMOD_CREATE_DEFAULT, NullLightObj()).mLgObj;
}
// ------------------------------------------------------------------------------------------------
@ -1507,30 +1527,30 @@ SQMOD_NODISCARD static int LgBindKey(bool down, int key1, int key2, int key3)
SQMOD_NODISCARD static bool LgRemoveKeybind(int id) { return _Func->RemoveKeyBind(id) == vcmpErrorNone; }
static void LgRemoveAllKeybinds() { _Func->RemoveAllKeyBinds(); }
// ------------------------------------------------------------------------------------------------
SQMOD_NODISCARD static bool LgGetCinematicBorder(LgPlayer & player) { return _Func->GetPlayerOption(player.GetIdentifier(), vcmpPlayerOptionWidescreen) >= 1; }
SQMOD_NODISCARD static bool LgGetGreenScanLines(LgPlayer & player) { return _Func->GetPlayerOption(player.GetIdentifier(), vcmpPlayerOptionGreenScanlines) >= 1; }
SQMOD_NODISCARD static bool LgGetWhiteScanLines(LgPlayer & player) { return _Func->GetPlayerOption(player.GetIdentifier(), vcmpPlayerOptionWhiteScanlines) >= 1; }
static void LgSetCinematicBorder(LgPlayer & player, bool toggle) { _Func->SetPlayerOption(player.GetIdentifier(), vcmpPlayerOptionWidescreen, static_cast< uint8_t >(toggle)); }
static void LgSetGreenScanLines(LgPlayer & player, bool toggle) { _Func->SetPlayerOption(player.GetIdentifier(), vcmpPlayerOptionGreenScanlines, static_cast< uint8_t >(toggle)); }
static void LgSetWhiteScanLines(LgPlayer & player, bool toggle) { _Func->SetPlayerOption(player.GetIdentifier(), vcmpPlayerOptionWhiteScanlines, static_cast< uint8_t >(toggle)); }
SQMOD_NODISCARD static bool LgGetCinematicBorder(LightObj & player) { return _Func->GetPlayerOption(GetLgEntID< LgPlayer, CPlayer >(player), vcmpPlayerOptionWidescreen) >= 1; }
SQMOD_NODISCARD static bool LgGetGreenScanLines(LightObj & player) { return _Func->GetPlayerOption(GetLgEntID< LgPlayer, CPlayer >(player), vcmpPlayerOptionGreenScanlines) >= 1; }
SQMOD_NODISCARD static bool LgGetWhiteScanLines(LightObj & player) { return _Func->GetPlayerOption(GetLgEntID< LgPlayer, CPlayer >(player), vcmpPlayerOptionWhiteScanlines) >= 1; }
static void LgSetCinematicBorder(LightObj & player, bool toggle) { _Func->SetPlayerOption(GetLgEntID< LgPlayer, CPlayer >(player), vcmpPlayerOptionWidescreen, static_cast< uint8_t >(toggle)); }
static void LgSetGreenScanLines(LightObj & player, bool toggle) { _Func->SetPlayerOption(GetLgEntID< LgPlayer, CPlayer >(player), vcmpPlayerOptionGreenScanlines, static_cast< uint8_t >(toggle)); }
static void LgSetWhiteScanLines(LightObj & player, bool toggle) { _Func->SetPlayerOption(GetLgEntID< LgPlayer, CPlayer >(player), vcmpPlayerOptionWhiteScanlines, static_cast< uint8_t >(toggle)); }
// ------------------------------------------------------------------------------------------------
static void LgKickPlayer(LgPlayer & player) { _Func->KickPlayer(player.GetIdentifier()); }
static void LgBanPlayer(LgPlayer & player) { _Func->BanPlayer(player.GetIdentifier()); }
static void LgKickPlayer(LightObj & player) { _Func->KickPlayer(GetLgEntID< LgPlayer, CPlayer >(player)); }
static void LgBanPlayer(LightObj & player) { _Func->BanPlayer(GetLgEntID< LgPlayer, CPlayer >(player)); }
// ------------------------------------------------------------------------------------------------
static void LgMessage(StackStrF & msg) { _Func->SendClientMessage(-1, 0x0b5fa5ff, "%s", msg.mPtr); }
static void LgMessagePlayer(StackStrF & msg, LgPlayer & player) { _Func->SendClientMessage(player.GetIdentifier(), 0x0b5fa5ff, "%s", msg.mPtr); }
static void LgMessageAllExcept(StackStrF & msg, LgPlayer & player) {
const int32_t p = player.GetIdentifier();
static void LgMessagePlayer(StackStrF & msg, LightObj & player) { _Func->SendClientMessage(GetLgEntID< LgPlayer, CPlayer >(player), 0x0b5fa5ff, "%s", msg.mPtr); }
static void LgMessageAllExcept(StackStrF & msg, LightObj & player) {
const auto p = GetLgEntID< LgPlayer, CPlayer >(player);
const SQChar * m = msg.mPtr;
ForeachConnectedPlayer([=](int32_t id) { if (id != p) _Func->SendClientMessage(id, 0x0b5fa5ff, "%s", m); });
}
static void LgPrivMessage(LgPlayer & player, StackStrF & msg) { _Func->SendClientMessage(player.GetIdentifier(), 0x007f16ff, "** pm >> %s", msg.mPtr); }
static void LgPrivMessage(LightObj & player, StackStrF & msg) { _Func->SendClientMessage(GetLgEntID< LgPlayer, CPlayer >(player), 0x007f16ff, "** pm >> %s", msg.mPtr); }
static void LgPrivMessageAll(StackStrF & msg) {
const SQChar * m = msg.mPtr;
ForeachConnectedPlayer([=](int32_t id) { _Func->SendClientMessage(id, 0x007f16ff, "** pm >> %s", m); });
}
static void LgSendPlayerMessage(LgPlayer & source, LgPlayer & target, StackStrF & msg) {
_Func->SendClientMessage(target.GetIdentifier(), 0x007f16ff, "** pm from %s >> %s", source.Get().GetName(), msg.mPtr);
static void LgSendPlayerMessage(LightObj & source, LightObj & target, StackStrF & msg) {
_Func->SendClientMessage(GetLgEntID< LgPlayer, CPlayer >(target), 0x007f16ff, "** pm from %s >> %s",GetNativeEnt< LgPlayer, CPlayer >(source).GetName(), msg.mPtr);
}
// ------------------------------------------------------------------------------------------------
SQMOD_NODISCARD static const SQChar * LgGetWeaponName(int id) { return GetWeaponName(static_cast< uint32_t >(id)); }
@ -2302,8 +2322,8 @@ struct LgStream {
int32_t id;
if (target.IsNull()) id = -1;
else if (target.GetType() == OT_INTEGER || target.GetType() == OT_FLOAT) id = target.Cast< int32_t >();
else if (static_cast< AbstractStaticClassData * >(target.GetTypeTag()) == StaticClassTypeTag< LgPlayer >::Get()) {
id = target.CastI< LgPlayer >()->GetIdentifier();
else if (target.GetType() == OT_INSTANCE) {
id = GetLgEntID< LgPlayer, CPlayer >(target);
} else STHROWF("Invalid target type");
if (id >= SQMOD_PLAYER_POOL) STHROWF("Invalid player ID");
_Func->SendClientScriptData(id, m_OutputStreamData, m_OutputStreamEnd);

View File

@ -2146,12 +2146,12 @@ struct SqDataAsyncBuilder
SqDataAsyncBuilder & operator = (SqDataAsyncBuilder && o) = default;
/* --------------------------------------------------------------------------------------------
* Create the task with the suplied information and submit it to the worker pool.
* Create the task with the supplied information and submit it to the worker pool.
*/
void Submit() { Submit_(NullLightObj()); }
/* --------------------------------------------------------------------------------------------
* Create the task with the suplied information and submit it to the worker pool.
* Create the task with the supplied information and submit it to the worker pool.
*/
void Submit_(LightObj & ctx);

View File

@ -195,21 +195,7 @@ struct LightObj {
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
template<class T, class... A>
LightObj(SqTypeIdentity< T > SQ_UNUSED_ARG(t), HSQUIRRELVM vm, A&&... a) {
// Create the instance and guard it to make sure it gets deleted in case of exceptions
DeleteGuard< T > instance(new T(std::forward< A >(a)...));
// Preserve the stack state
const StackGuard sg(vm);
// Push the instance on the stack
ClassType<T>::PushInstance(vm, instance);
// Attempt to retrieve it
if (SQ_FAILED(sq_getstackobj(vm, -1, &mObj))) {
sq_resetobject(&mObj);
} else {
sq_addref(vm, &mObj);
}
// Stop guarding the instance
instance.Release();
LightObj(SqTypeIdentity< T > SQ_UNUSED_ARG(t), HSQUIRRELVM vm, A&&... a) : LightObj(DeleteGuard< T >(new T(std::forward< A >(a)...))) {
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@ -246,7 +232,21 @@ struct LightObj {
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
template<class T>
LightObj(DeleteGuard<T> guard, HSQUIRRELVM v = SqVM()) : LightObj(guard.Get(), v) {
LightObj(DeleteGuard<T> && guard, HSQUIRRELVM v = SqVM()) : LightObj(guard.Get(), v) {
guard.Release();
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Constructs an LightObj from a C++ instance wrapped inside a DeleteGuard
///
/// \param instance Pointer to a C++ class instance that has been bound already
/// \param v VM that the object will exist in
///
/// \tparam T Type of instance
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
template<class T>
LightObj(DeleteGuard<T> & guard, HSQUIRRELVM v = SqVM()) : LightObj(guard.Get(), v) {
guard.Release();
}

View File

@ -35,6 +35,7 @@
#include <string>
#include <utility>
#include <exception>
#include <type_traits>
#include <unordered_map>
#include <Poco/Exception.h>
@ -1580,12 +1581,31 @@ public:
}
};
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Helper structure for one element from the top of stack. Uses default global VM instead.
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
struct SqPopTopGuardLite
{
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Base constructor.
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
SqPopTopGuardLite() noexcept = default;
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Destructor. Pops the specified elements from the stack.
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
~SqPopTopGuardLite()
{
sq_poptop(SqVM());
}
};
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Helper structure for one element from the top of stack.
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
struct SqPopTopGuard
{
HSQUIRRELVM mVM; // The VM from which the elements must be popped.
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Base constructor.
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@ -1603,13 +1623,70 @@ struct SqPopTopGuard
}
};
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Helper structure for popping elements from the stack. Uses default global VM instead.
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
struct SqPopGuardLite
{
SQInteger mNum{0}; // The number of elements to be popped.
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Base constructor.
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
explicit SqPopGuardLite(SQInteger num) noexcept
: mNum(num)
{
//...
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Destructor. Pops the specified elements from the stack.
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
~SqPopGuardLite()
{
sq_pop(SqVM(), mNum);
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Increment the number of elements to be popped.
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
SqPopGuardLite & operator ++ ()
{
++mNum;
return *this;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Decrement the number of elements to be popped.
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
SqPopGuardLite & operator -- ()
{
--mNum;
return *this;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Increase the number of elements to be popped.
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
SqPopGuardLite & operator += (SQInteger n)
{
mNum += n;
return *this;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Decrease the number of elements to be popped.
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
SqPopGuardLite & operator -= (SQInteger n)
{
mNum -= n;
return *this;
}
};
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Helper structure for popping elements from the stack.
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
struct SqPopGuard
{
HSQUIRRELVM mVM; // The VM from which the elements must be popped.
SQInteger mNum; // The number of elements to be popped.
HSQUIRRELVM mVM{nullptr}; // The VM from which the elements must be popped.
SQInteger mNum{0}; // The number of elements to be popped.
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Base constructor.
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@ -1659,17 +1736,79 @@ struct SqPopGuard
}
};
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Implements RAII to restore the VM stack to it's initial size on function exit. Uses default global VM instead.
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
struct StackGuardLite
{
SQInteger mTop{0}; ///< The top of the stack when this instance was created.
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Default constructor.
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
StackGuardLite() noexcept
: mTop(sq_gettop(SqVM()))
{
/* ... */
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Copy constructor. (disabled)
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
StackGuardLite(const StackGuardLite &) = delete;
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Move constructor. (disabled)
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
StackGuardLite(StackGuardLite &&) = delete;
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Destructor.
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
~StackGuardLite()
{
Restore();
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Copy assignment operator. (disabled)
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
StackGuardLite & operator = (const StackGuardLite &) = delete;
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Move assignment operator. (disabled)
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
StackGuardLite & operator = (StackGuardLite &&) = delete;
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Restore the stack to what was known to be.
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void Restore() const
{
auto vm = SqVM();
// Retrieve the new stack top
const SQInteger top = sq_gettop(vm);
// Did the stack size change?
if (top > mTop)
{
sq_pop(vm, top - mTop); // Trim the stack
}
}
};
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Implements RAII to restore the VM stack to it's initial size on function exit.
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
struct StackGuard
{
HSQUIRRELVM mVM{nullptr}; ///< The VM where the stack should be restored.
SQInteger mTop{0}; ///< The top of the stack when this instance was created.
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Default constructor.
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
StackGuard()
: m_VM(SqVM()), m_Top(sq_gettop(m_VM))
: mVM(SqVM()), mTop(sq_gettop(mVM))
{
/* ... */
}
@ -1677,8 +1816,8 @@ struct StackGuard
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Base constructor.
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
StackGuard(HSQUIRRELVM vm)
: m_VM(vm), m_Top(sq_gettop(vm))
explicit StackGuard(HSQUIRRELVM vm)
: mVM(vm), mTop(sq_gettop(vm))
{
/* ... */
}
@ -1717,18 +1856,13 @@ struct StackGuard
void Restore() const
{
// Retrieve the new stack top
const SQInteger top = sq_gettop(m_VM);
const SQInteger top = sq_gettop(mVM);
// Did the stack size change?
if (top > m_Top)
if (top > mTop)
{
sq_pop(m_VM, top - m_Top); // Trim the stack
sq_pop(mVM, top - mTop); // Trim the stack
}
}
private:
HSQUIRRELVM m_VM; ///< The VM where the stack should be restored.
SQInteger m_Top; ///< The top of the stack when this instance was created.
};
@ -2131,18 +2265,13 @@ inline void ErrorToException(HSQUIRRELVM vm, bool keep = false) {
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
template < typename T > struct DeleteGuard
{
private:
// --------------------------------------------------------------------------------------------
T * m_Ptr; // Pointer to the instance to manage.
public:
T * mPtr; // Pointer to the instance to manage.
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Default constructor.
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
explicit DeleteGuard(T * ptr)
: m_Ptr(ptr)
: mPtr(ptr)
{
/* ... */
}
@ -2152,7 +2281,7 @@ public:
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
template<class... A>
explicit DeleteGuard(SqInPlace SQ_UNUSED_ARG(t), A&&... a)
: m_Ptr(new T(std::forward< A >(a)...))
: mPtr(new T(std::forward< A >(a)...))
{
/* ... */
}
@ -2166,9 +2295,9 @@ public:
/// Move constructor.
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
DeleteGuard(DeleteGuard && o) noexcept
: m_Ptr(o.m_Ptr)
: mPtr(o.mPtr)
{
o.m_Ptr = nullptr;
o.mPtr = nullptr;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@ -2176,9 +2305,9 @@ public:
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
~DeleteGuard()
{
if (m_Ptr)
if (mPtr)
{
delete m_Ptr;
delete mPtr;
}
}
@ -2197,7 +2326,7 @@ public:
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
operator T * () const
{
return m_Ptr;
return mPtr;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@ -2205,7 +2334,7 @@ public:
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
T * Get() const
{
return m_Ptr;
return mPtr;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@ -2213,7 +2342,7 @@ public:
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void Release()
{
m_Ptr = nullptr;
mPtr = nullptr;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@ -2221,8 +2350,8 @@ public:
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
T * Grab()
{
T * ptr = m_Ptr;
m_Ptr = nullptr;
T * ptr = mPtr;
mPtr = nullptr;
return ptr;
}
};
@ -2320,18 +2449,13 @@ template < typename T > T * SqChainedInstances< T >::sHead = nullptr;
/// @cond DEV
/// Used internally to get and manipulate the underlying type of variables - retrieved from cppreference.com
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
template<class T> struct remove_const {typedef T type;};
template<class T> struct remove_const<const T> {typedef T type;};
template<class T> struct remove_volatile {typedef T type;};
template<class T> struct remove_volatile<volatile T> {typedef T type;};
template<class T> struct remove_cv {typedef typename remove_volatile<typename remove_const<T>::type>::type type;};
template<class T> struct is_pointer_helper {static constexpr bool value = false;};
template<class T> struct is_pointer_helper<T*> {static constexpr bool value = true;};
template<class T,class D> struct is_pointer_helper<SharedPtr<T,D> > {static constexpr bool value = true;};
template<class T,class D> struct is_pointer_helper<WeakPtr<T,D> > {static constexpr bool value = true;};
template<class T> struct is_pointer : is_pointer_helper<typename remove_cv<T>::type> {};
template<class T> struct is_reference {static constexpr bool value = false;};
template<class T> struct is_reference<T&> {static constexpr bool value = true;};
template<class T> using remove_const = std::remove_const< T >;
template<class T> using remove_volatile = std::remove_volatile< T >;
template<class T> using remove_cv = std::remove_cv< T >;
template<class T> struct is_pointer : public std::is_pointer< T > { };
template<class T,class D> struct is_pointer<SharedPtr<T,D> > : public std::true_type { };
template<class T,class D> struct is_pointer<WeakPtr<T,D> > : public std::true_type { };
template<class T> using is_reference = std::is_lvalue_reference< T >;
/// @endcond