Skip to content
81 changes: 45 additions & 36 deletions Shared/mods/deathmatch/logic/lua/CLuaFunctionParser.h
Original file line number Diff line number Diff line change
Expand Up @@ -352,19 +352,41 @@ struct CLuaFunctionParserBase
if constexpr (std::is_same_v<T, dummy_type>)
return dummy_type{};
// primitive types are directly popped
else if constexpr (std::is_same_v<T, std::string> || std::is_same_v<T, std::string_view> || std::is_integral_v<T>)
else if constexpr (std::is_same_v<T, std::string> || std::is_same_v<T, std::string_view>)
return lua::PopPrimitive<T>(L, index);
// floats/doubles may not be NaN
else if constexpr (std::is_same_v<T, float> || std::is_same_v<T, double>)
else if constexpr (std::is_same_v<T, bool>)
return lua::PopPrimitive<T>(L, index);
else if constexpr (std::is_integral_v<T> || std::is_floating_point_v<T>) // bool is an integral type, so must pop it before ^^
{
T value = lua::PopPrimitive<T>(L, index);
if (std::isnan(value))
{
const auto number = lua::PopPrimitive<lua_Number>(L, index);

const auto SetError = [&](const char* expected, const char* got) {
// Subtract one from the index, as the call to lua::PopPrimitive above increments the index, even if the
// underlying element is of a wrong type
SetBadArgumentError(L, "number", index - 1, "NaN");
SetBadArgumentError(L, expected, index - 1, got);
};

if (std::isnan(number))
{
SetError("number", "NaN");
return static_cast<T>(number);
}

if (std::isinf(number)) {
SetError("number", "inf");
return static_cast<T>(number);
}
return value;

// NOTE/TODO: Use C++20 `std::in_range` here instead
// For now this doesn't do all the safety checks, but this should be "good enough" [until we switch to C++20]
if constexpr (std::is_integral_v<T> && std::is_unsigned_v<T>)
{
SetError("positive number", "negative");

return static_cast<T>(static_cast<int64_t>(number));
}

return static_cast<T>(number);
}
else if constexpr (std::is_enum_v<T>)
{
Expand Down Expand Up @@ -488,10 +510,7 @@ struct CLuaFunctionParserBase
{
if (lua_isnumber(L, index))
{
CVector2D vec;
vec.fX = lua::PopPrimitive<float>(L, index);
vec.fY = lua::PopPrimitive<float>(L, index);
return vec;
return { PopUnsafe<float>(L, index), PopUnsafe<float>(L, index) };
}
else
{
Expand Down Expand Up @@ -520,11 +539,7 @@ struct CLuaFunctionParserBase
{
if (lua_isnumber(L, index))
{
CVector vec;
vec.fX = lua::PopPrimitive<float>(L, index);
vec.fY = lua::PopPrimitive<float>(L, index);
vec.fZ = lua::PopPrimitive<float>(L, index);
return vec;
return { PopUnsafe<float>(L, index), PopUnsafe<float>(L, index), PopUnsafe<float>(L, index) };
}
else
{
Expand All @@ -551,12 +566,8 @@ struct CLuaFunctionParserBase
{
if (lua_isnumber(L, index))
{
CVector4D vec;
vec.fX = lua::PopPrimitive<float>(L, index);
vec.fY = lua::PopPrimitive<float>(L, index);
vec.fZ = lua::PopPrimitive<float>(L, index);
vec.fW = lua::PopPrimitive<float>(L, index);
return vec;
return { PopUnsafe<float>(L, index), PopUnsafe<float>(L, index),
PopUnsafe<float>(L, index), PopUnsafe<float>(L, index) };
}
else
{
Expand All @@ -583,19 +594,17 @@ struct CLuaFunctionParserBase
{
if (lua_isnumber(L, index))
{
const auto ReadVector = [&] {
return CVector(PopUnsafe<float>(L, index), PopUnsafe<float>(L, index), PopUnsafe<float>(L, index));
};

CMatrix matrix;
matrix.vRight.fX = lua::PopPrimitive<float>(L, index);
matrix.vRight.fY = lua::PopPrimitive<float>(L, index);
matrix.vRight.fZ = lua::PopPrimitive<float>(L, index);
matrix.vFront.fX = lua::PopPrimitive<float>(L, index);
matrix.vFront.fY = lua::PopPrimitive<float>(L, index);
matrix.vFront.fZ = lua::PopPrimitive<float>(L, index);
matrix.vUp.fX = lua::PopPrimitive<float>(L, index);
matrix.vUp.fY = lua::PopPrimitive<float>(L, index);
matrix.vUp.fZ = lua::PopPrimitive<float>(L, index);
matrix.vPos.fX = lua::PopPrimitive<float>(L, index);
matrix.vPos.fY = lua::PopPrimitive<float>(L, index);
matrix.vPos.fZ = lua::PopPrimitive<float>(L, index);

matrix.vRight = ReadVector();
matrix.vFront = ReadVector();
matrix.vUp = ReadVector();
matrix.vPos = ReadVector();

return matrix;
}
else
Expand Down Expand Up @@ -635,7 +644,7 @@ struct CLuaFunctionParserBase
return static_cast<T>(result);
}
else if constexpr (std::is_same_v<T, SColor>)
return static_cast<unsigned long>(lua::PopPrimitive<int64_t>(L, index));
return static_cast<unsigned long>(static_cast<int64_t>(lua::PopPrimitive<lua_Number>(L, index)));
else if constexpr (std::is_same_v<T, CLuaArgument>)
{
CLuaArgument argument;
Expand Down
68 changes: 8 additions & 60 deletions Shared/mods/deathmatch/logic/lua/LuaBasic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,66 +29,6 @@ namespace lua
return outValue;
}

template <>
int PopPrimitive<int>(lua_State* L, int& index)
{
return static_cast<int>(lua_tonumber(L, index++));
}

template <>
unsigned int PopPrimitive<unsigned int>(lua_State* L, int& index)
{
return static_cast<unsigned int>(lua_tonumber(L, index++));
}

template <>
short PopPrimitive<short>(lua_State* L, int& index)
{
return static_cast<short>(lua_tonumber(L, index++));
}

template <>
unsigned short PopPrimitive<unsigned short>(lua_State* L, int& index)
{
return static_cast<unsigned short>(lua_tonumber(L, index++));
}

template <>
char PopPrimitive<char>(lua_State* L, int& index)
{
return static_cast<char>(lua_tonumber(L, index++));
}

template <>
unsigned char PopPrimitive<unsigned char>(lua_State* L, int& index)
{
return static_cast<unsigned char>(lua_tonumber(L, index++));
}

template <>
int64_t PopPrimitive<int64_t>(lua_State* L, int& index)
{
return static_cast<int64_t>(lua_tonumber(L, index++));
}

template <>
uint64_t PopPrimitive<uint64_t>(lua_State* L, int& index)
{
return static_cast<uint64_t>(lua_tonumber(L, index++));
}

template <>
float PopPrimitive<float>(lua_State* L, int& index)
{
return static_cast<float>(lua_tonumber(L, index++));
}

template <>
double PopPrimitive<double>(lua_State* L, int& index)
{
return static_cast<double>(lua_tonumber(L, index++));
}

template <>
bool PopPrimitive<bool>(lua_State* L, int& index)
{
Expand All @@ -100,4 +40,12 @@ namespace lua
{
return lua_touserdata(L, index++);
}

template<>
lua_Number PopPrimitive<lua_Number>(lua_State* L, int& index)
{
return lua_tonumber(L, index++);
}

// Int types aren't Poppable directly, because they need to be checked for under/overflow, NaN, inf
} // namespace lua