From 8f3005e9b24fa95a324d52fd9595fdc20c6c2c23 Mon Sep 17 00:00:00 2001 From: Huoji's <1296564236@qq.com> Date: Tue, 3 Oct 2023 04:07:50 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A4=A7=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- csgo2/LuaBridge/luaBridge/Array.h | 62 + csgo2/LuaBridge/luaBridge/List.h | 51 + csgo2/LuaBridge/luaBridge/LuaBridge.h | 34 + csgo2/LuaBridge/luaBridge/Map.h | 52 + csgo2/LuaBridge/luaBridge/Optional.h | 46 + csgo2/LuaBridge/luaBridge/Pair.h | 77 + csgo2/LuaBridge/luaBridge/RefCountedObject.h | 317 ++++ csgo2/LuaBridge/luaBridge/RefCountedPtr.h | 226 +++ csgo2/LuaBridge/luaBridge/UnorderedMap.h | 51 + csgo2/LuaBridge/luaBridge/Vector.h | 50 + csgo2/LuaBridge/luaBridge/detail/CFunctions.h | 470 +++++ csgo2/LuaBridge/luaBridge/detail/ClassInfo.h | 140 ++ csgo2/LuaBridge/luaBridge/detail/Config.h | 7 + .../LuaBridge/luaBridge/detail/Constructor.h | 225 +++ csgo2/LuaBridge/luaBridge/detail/FuncTraits.h | 435 +++++ csgo2/LuaBridge/luaBridge/detail/Iterator.h | 150 ++ .../LuaBridge/luaBridge/detail/LuaException.h | 104 ++ csgo2/LuaBridge/luaBridge/detail/LuaHelpers.h | 126 ++ csgo2/LuaBridge/luaBridge/detail/LuaRef.h | 1012 +++++++++++ csgo2/LuaBridge/luaBridge/detail/Namespace.h | 1395 +++++++++++++++ csgo2/LuaBridge/luaBridge/detail/Security.h | 58 + csgo2/LuaBridge/luaBridge/detail/Stack.h | 535 ++++++ csgo2/LuaBridge/luaBridge/detail/TypeList.h | 183 ++ csgo2/LuaBridge/luaBridge/detail/TypeTraits.h | 112 ++ csgo2/LuaBridge/luaBridge/detail/Userdata.h | 769 ++++++++ csgo2/LuaBridge/luaBridge/detail/dump.h | 125 ++ csgo2/csgo2.vcxproj | 13 +- csgo2/csgo2.vcxproj.filters | 27 + csgo2/events.cpp | 12 +- csgo2/head.h | 15 +- csgo2/native_sdk.cpp | 136 +- csgo2/native_sdk.h | 265 ++- csgo2/offset.cpp | 28 +- csgo2/offset.h | 12 +- csgo2/script_apis.cpp | 114 +- csgo2/script_callbacks.cpp | 6 +- csgo2/script_callbacks.h | 2 +- csgo2/script_engine.cpp | 3 +- csgo2/sdk/public/bitvec.h | 1397 +++++++++++++++ csgo2/sdk/public/eiface.h | 109 +- csgo2/sdk/public/iserver.h | 133 ++ csgo2/sdk/public/mathlib.h | 12 + csgo2/sdk/public/string_t.h | 114 ++ csgo2/sdk/public/utlmap.h | 200 +++ csgo2/sdk/public/utlrbtree.h | 1546 +++++++++++++++++ csgo2/sdk/sdk.h | 29 + csgo2/sdk/tier1/UtlVector.hpp | 2 +- csgo2/sdk/tier1/utlblockmemory.h | 345 ++++ csgo2/sdk/tier1/utlfixedmemory.h | 337 ++++ csgo2/vector.h | 404 +++++ 50 files changed, 11966 insertions(+), 107 deletions(-) create mode 100644 csgo2/LuaBridge/luaBridge/Array.h create mode 100644 csgo2/LuaBridge/luaBridge/List.h create mode 100644 csgo2/LuaBridge/luaBridge/LuaBridge.h create mode 100644 csgo2/LuaBridge/luaBridge/Map.h create mode 100644 csgo2/LuaBridge/luaBridge/Optional.h create mode 100644 csgo2/LuaBridge/luaBridge/Pair.h create mode 100644 csgo2/LuaBridge/luaBridge/RefCountedObject.h create mode 100644 csgo2/LuaBridge/luaBridge/RefCountedPtr.h create mode 100644 csgo2/LuaBridge/luaBridge/UnorderedMap.h create mode 100644 csgo2/LuaBridge/luaBridge/Vector.h create mode 100644 csgo2/LuaBridge/luaBridge/detail/CFunctions.h create mode 100644 csgo2/LuaBridge/luaBridge/detail/ClassInfo.h create mode 100644 csgo2/LuaBridge/luaBridge/detail/Config.h create mode 100644 csgo2/LuaBridge/luaBridge/detail/Constructor.h create mode 100644 csgo2/LuaBridge/luaBridge/detail/FuncTraits.h create mode 100644 csgo2/LuaBridge/luaBridge/detail/Iterator.h create mode 100644 csgo2/LuaBridge/luaBridge/detail/LuaException.h create mode 100644 csgo2/LuaBridge/luaBridge/detail/LuaHelpers.h create mode 100644 csgo2/LuaBridge/luaBridge/detail/LuaRef.h create mode 100644 csgo2/LuaBridge/luaBridge/detail/Namespace.h create mode 100644 csgo2/LuaBridge/luaBridge/detail/Security.h create mode 100644 csgo2/LuaBridge/luaBridge/detail/Stack.h create mode 100644 csgo2/LuaBridge/luaBridge/detail/TypeList.h create mode 100644 csgo2/LuaBridge/luaBridge/detail/TypeTraits.h create mode 100644 csgo2/LuaBridge/luaBridge/detail/Userdata.h create mode 100644 csgo2/LuaBridge/luaBridge/detail/dump.h create mode 100644 csgo2/sdk/public/bitvec.h create mode 100644 csgo2/sdk/public/iserver.h create mode 100644 csgo2/sdk/public/mathlib.h create mode 100644 csgo2/sdk/public/string_t.h create mode 100644 csgo2/sdk/public/utlmap.h create mode 100644 csgo2/sdk/public/utlrbtree.h create mode 100644 csgo2/sdk/tier1/utlblockmemory.h create mode 100644 csgo2/sdk/tier1/utlfixedmemory.h create mode 100644 csgo2/vector.h diff --git a/csgo2/LuaBridge/luaBridge/Array.h b/csgo2/LuaBridge/luaBridge/Array.h new file mode 100644 index 0000000..6fba22e --- /dev/null +++ b/csgo2/LuaBridge/luaBridge/Array.h @@ -0,0 +1,62 @@ +// https://github.com/vinniefalco/LuaBridge +// +// Copyright 2020, Dmitry Tarakanov +// SPDX-License-Identifier: MIT + +#pragma once + +#include + +#include + +namespace luabridge { + +template +struct Stack> +{ + static void push(lua_State* L, std::array const& array) + { + lua_createtable(L, static_cast(s), 0); + for (std::size_t i = 0; i < s; ++i) + { + lua_pushinteger(L, static_cast(i + 1)); + Stack::push(L, array[i]); + lua_settable(L, -3); + } + } + + static std::array get(lua_State* L, int index) + { + if (!lua_istable(L, index)) + { + luaL_error(L, "#%d argument must be table", index); + } + + std::size_t const tableSize = static_cast(get_length(L, index)); + + if (tableSize != s) + { + luaL_error(L, "array size must be %d ", s); + } + + std::array array; + + int const absindex = lua_absindex(L, index); + lua_pushnil(L); + int arrayIndex = 0; + while (lua_next(L, absindex) != 0) + { + array[arrayIndex] = Stack::get(L, -1); + lua_pop(L, 1); + ++arrayIndex; + } + return array; + } + + static bool isInstance(lua_State* L, int index) + { + return lua_istable(L, index) && get_length(L, index) == s; + } +}; + +} // namespace luabridge diff --git a/csgo2/LuaBridge/luaBridge/List.h b/csgo2/LuaBridge/luaBridge/List.h new file mode 100644 index 0000000..6c35728 --- /dev/null +++ b/csgo2/LuaBridge/luaBridge/List.h @@ -0,0 +1,51 @@ +// https://github.com/vinniefalco/LuaBridge +// Copyright 2020, Dmitry Tarakanov +// SPDX-License-Identifier: MIT + +#pragma once + +#include + +#include + +namespace luabridge { + +template +struct Stack> +{ + static void push(lua_State* L, std::list const& list) + { + lua_createtable(L, static_cast(list.size()), 0); + typename std::list::const_iterator item = list.begin(); + for (std::size_t i = 1; i <= list.size(); ++i) + { + lua_pushinteger(L, static_cast(i)); + Stack::push(L, *item); + lua_settable(L, -3); + ++item; + } + } + + static std::list get(lua_State* L, int index) + { + if (!lua_istable(L, index)) + { + luaL_error(L, "#%d argument must be a table", index); + } + + std::list list; + + int const absindex = lua_absindex(L, index); + lua_pushnil(L); + while (lua_next(L, absindex) != 0) + { + list.push_back(Stack::get(L, -1)); + lua_pop(L, 1); + } + return list; + } + + static bool isInstance(lua_State* L, int index) { return lua_istable(L, index); } +}; + +} // namespace luabridge diff --git a/csgo2/LuaBridge/luaBridge/LuaBridge.h b/csgo2/LuaBridge/luaBridge/LuaBridge.h new file mode 100644 index 0000000..91a07d8 --- /dev/null +++ b/csgo2/LuaBridge/luaBridge/LuaBridge.h @@ -0,0 +1,34 @@ +// https://github.com/vinniefalco/LuaBridge +// Copyright 2020, Dmitry Tarakanov +// Copyright 2012, Vinnie Falco +// Copyright 2007, Nathan Reed +// SPDX-License-Identifier: MIT + +#pragma once + +// All #include dependencies are listed here +// instead of in the individual header files. +// + +#define LUABRIDGE_MAJOR_VERSION 2 +#define LUABRIDGE_MINOR_VERSION 7 +#define LUABRIDGE_VERSION 207 + +#ifndef LUA_VERSION_NUM +#error "Lua headers must be included prior to LuaBridge ones" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include diff --git a/csgo2/LuaBridge/luaBridge/Map.h b/csgo2/LuaBridge/luaBridge/Map.h new file mode 100644 index 0000000..bd7e592 --- /dev/null +++ b/csgo2/LuaBridge/luaBridge/Map.h @@ -0,0 +1,52 @@ +// https://github.com/vinniefalco/LuaBridge +// Copyright 2018, Dmitry Tarakanov +// SPDX-License-Identifier: MIT + +#pragma once + +#include +#include + +#include + +namespace luabridge { + +template +struct Stack> +{ + typedef std::map Map; + + static void push(lua_State* L, const Map& map) + { + lua_createtable(L, 0, static_cast(map.size())); + typedef typename Map::const_iterator ConstIter; + for (ConstIter i = map.begin(); i != map.end(); ++i) + { + Stack::push(L, i->first); + Stack::push(L, i->second); + lua_settable(L, -3); + } + } + + static Map get(lua_State* L, int index) + { + if (!lua_istable(L, index)) + { + luaL_error(L, "#%d argument must be a table", index); + } + + Map map; + int const absindex = lua_absindex(L, index); + lua_pushnil(L); + while (lua_next(L, absindex) != 0) + { + map.emplace(Stack::get(L, -2), Stack::get(L, -1)); + lua_pop(L, 1); + } + return map; + } + + static bool isInstance(lua_State* L, int index) { return lua_istable(L, index); } +}; + +} // namespace luabridge diff --git a/csgo2/LuaBridge/luaBridge/Optional.h b/csgo2/LuaBridge/luaBridge/Optional.h new file mode 100644 index 0000000..d4e11fa --- /dev/null +++ b/csgo2/LuaBridge/luaBridge/Optional.h @@ -0,0 +1,46 @@ +// https://github.com/vinniefalco/LuaBridge +// Copyright 2021, Stefan Frings +// SPDX-License-Identifier: MIT + +#pragma once + +#include + +#include + +namespace luabridge { + +template +struct Stack> +{ + static void push(lua_State* L, std::optional const& optional) + { + if (optional) + { + Stack::push(L, *optional); + } + else + { + lua_pushnil(L); + } + } + + static std::optional get(lua_State* L, int index) + { + if (lua_isnil(L, index)) + { + lua_pop(L, 1); + + return std::nullopt; + } + + return Stack::get(L, index); + } + + static bool isInstance(lua_State* L, int index) + { + return lua_isnil(L, index) || Stack::isInstance(L, index); + } +}; + +} // namespace luabridge diff --git a/csgo2/LuaBridge/luaBridge/Pair.h b/csgo2/LuaBridge/luaBridge/Pair.h new file mode 100644 index 0000000..11e45cf --- /dev/null +++ b/csgo2/LuaBridge/luaBridge/Pair.h @@ -0,0 +1,77 @@ +// https://github.com/vinniefalco/LuaBridge +// Copyright 2022, Stefan Frings +// SPDX-License-Identifier: MIT + +#pragma once + +#include + +#include +#include + +namespace luabridge { + +template +struct Stack> +{ + static void push(lua_State* L, std::pair const& pair) + { + lua_createtable(L, 2, 0); + lua_pushinteger(L, static_cast(1)); + Stack::push(L, pair.first); + lua_settable(L, -3); + lua_pushinteger(L, static_cast(2)); + Stack::push(L, pair.second); + lua_settable(L, -3); + } + + static std::pair get(lua_State* L, int index) + { + if (!lua_istable(L, index)) + { + luaL_error(L, "#%d argument must be a table", index); + } + + std::size_t const tableSize = static_cast(get_length(L, index)); + + if (tableSize != 2) + { + luaL_error(L, "pair size must be 2"); + } + + std::pair pair; + + int const absindex = lua_absindex(L, index); + lua_pushnil(L); + + { + int const next = lua_next(L, absindex); + assert(next != 0); + + pair.first = Stack::get(L, -1); + lua_pop(L, 1); + } + + { + int const next = lua_next(L, absindex); + assert(next != 0); + + pair.second = Stack::get(L, -1); + lua_pop(L, 1); + } + + { + int const next = lua_next(L, absindex); + assert(next == 0); + } + + return pair; + } + + static bool isInstance(lua_State* L, int index) + { + return lua_istable(L, index) && get_length(L, index) == 2; + } +}; + +} // namespace luabridge diff --git a/csgo2/LuaBridge/luaBridge/RefCountedObject.h b/csgo2/LuaBridge/luaBridge/RefCountedObject.h new file mode 100644 index 0000000..f494312 --- /dev/null +++ b/csgo2/LuaBridge/luaBridge/RefCountedObject.h @@ -0,0 +1,317 @@ +// https://github.com/vinniefalco/LuaBridge +// Copyright 2012, Vinnie Falco +// Copyright 2004-11 by Raw Material Software Ltd. +// SPDX-License-Identifier: MIT + +//============================================================================== +/* + This is a derivative work used by permission from part of + JUCE, available at http://www.rawaterialsoftware.com + + License: The MIT License (http://www.opensource.org/licenses/mit-license.php) + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + + This file incorporates work covered by the following copyright and + permission notice: + + This file is part of the JUCE library - "Jules' Utility Class Extensions" + Copyright 2004-11 by Raw Material Software Ltd. +*/ +//============================================================================== + +#pragma once + +#include +#include + +namespace luabridge { + +//============================================================================== +/** + Adds reference-counting to an object. + + To add reference-counting to a class, derive it from this class, and + use the RefCountedObjectPtr class to point to it. + + e.g. @code + class MyClass : public RefCountedObjectType + { + void foo(); + + // This is a neat way of declaring a typedef for a pointer class, + // rather than typing out the full templated name each time.. + typedef RefCountedObjectPtr Ptr; + }; + + MyClass::Ptr p = new MyClass(); + MyClass::Ptr p2 = p; + p = 0; + p2->foo(); + @endcode + + Once a new RefCountedObjectType has been assigned to a pointer, be + careful not to delete the object manually. +*/ +template +class RefCountedObjectType +{ +public: + //============================================================================== + /** Increments the object's reference count. + + This is done automatically by the smart pointer, but is public just + in case it's needed for nefarious purposes. + */ + void incReferenceCount() const { ++refCount; } + + /** Decreases the object's reference count. + + If the count gets to zero, the object will be deleted. + */ + void decReferenceCount() const + { + assert(getReferenceCount() > 0); + + if (--refCount == 0) + delete this; + } + + /** Returns the object's current reference count. + * @returns The reference count. + */ + int getReferenceCount() const { return static_cast(refCount); } + +protected: + //============================================================================== + /** Creates the reference-counted object (with an initial ref count of zero). */ + RefCountedObjectType() : refCount() {} + + /** Destructor. */ + virtual ~RefCountedObjectType() + { + // it's dangerous to delete an object that's still referenced by something else! + assert(getReferenceCount() == 0); + } + +private: + //============================================================================== + CounterType mutable refCount; +}; + +//============================================================================== + +/** Non thread-safe reference counted object. + + This creates a RefCountedObjectType that uses a non-atomic integer + as the counter. +*/ +typedef RefCountedObjectType RefCountedObject; + +//============================================================================== +/** + A smart-pointer class which points to a reference-counted object. + + The template parameter specifies the class of the object you want to point + to - the easiest way to make a class reference-countable is to simply make + it inherit from RefCountedObjectType, but if you need to, you could roll + your own reference-countable class by implementing a pair of methods called + incReferenceCount() and decReferenceCount(). + + When using this class, you'll probably want to create a typedef to + abbreviate the full templated name - e.g. + + @code + + typedef RefCountedObjectPtr MyClassPtr; + + @endcode +*/ +template +class RefCountedObjectPtr +{ +public: + /** The class being referenced by this pointer. */ + typedef ReferenceCountedObjectClass ReferencedType; + + //============================================================================== + /** Creates a pointer to a null object. */ + RefCountedObjectPtr() : referencedObject(nullptr) {} + + /** Creates a pointer to an object. + This will increment the object's reference-count if it is non-null. + + @param refCountedObject A reference counted object to own. + */ + RefCountedObjectPtr(ReferenceCountedObjectClass* const refCountedObject) + : referencedObject(refCountedObject) + { + if (refCountedObject != nullptr) + refCountedObject->incReferenceCount(); + } + + /** Copies another pointer. + This will increment the object's reference-count (if it is non-null). + + @param other Another pointer. + */ + RefCountedObjectPtr(const RefCountedObjectPtr& other) : referencedObject(other.referencedObject) + { + if (referencedObject != nullptr) + referencedObject->incReferenceCount(); + } + + /** + Takes-over the object from another pointer. + + @param other Another pointer. + */ + RefCountedObjectPtr(RefCountedObjectPtr&& other) : referencedObject(other.referencedObject) + { + other.referencedObject = nullptr; + } + + /** Copies another pointer. + This will increment the object's reference-count (if it is non-null). + + @param other Another pointer. + */ + template + RefCountedObjectPtr(const RefCountedObjectPtr& other) + : referencedObject(static_cast(other.getObject())) + { + if (referencedObject != nullptr) + referencedObject->incReferenceCount(); + } + + /** Changes this pointer to point at a different object. + + The reference count of the old object is decremented, and it might be + deleted if it hits zero. The new object's count is incremented. + + @param other A pointer to assign from. + @returns This pointer. + */ + RefCountedObjectPtr& operator=(const RefCountedObjectPtr& other) + { + return operator=(other.referencedObject); + } + + /** Changes this pointer to point at a different object. + The reference count of the old object is decremented, and it might be + deleted if it hits zero. The new object's count is incremented. + + @param other A pointer to assign from. + @returns This pointer. + */ + template + RefCountedObjectPtr& operator=(const RefCountedObjectPtr& other) + { + return operator=(static_cast(other.getObject())); + } + + /** + Takes-over the object from another pointer. + + @param other A pointer to assign from. + @returns This pointer. + */ + RefCountedObjectPtr& operator=(RefCountedObjectPtr&& other) + { + std::swap(referencedObject, other.referencedObject); + return *this; + } + + /** Changes this pointer to point at a different object. + The reference count of the old object is decremented, and it might be + deleted if it hits zero. The new object's count is incremented. + + @param newObject A reference counted object to own. + @returns This pointer. + */ + RefCountedObjectPtr& operator=(ReferenceCountedObjectClass* const newObject) + { + if (referencedObject != newObject) + { + if (newObject != nullptr) + newObject->incReferenceCount(); + + ReferenceCountedObjectClass* const oldObject = referencedObject; + referencedObject = newObject; + + if (oldObject != nullptr) + oldObject->decReferenceCount(); + } + + return *this; + } + + /** Destructor. + This will decrement the object's reference-count, and may delete it if it + gets to zero. + */ + ~RefCountedObjectPtr() + { + if (referencedObject != nullptr) + referencedObject->decReferenceCount(); + } + + /** Returns the object that this pointer references. + The returned pointer may be null. + + @returns The pointee. + */ + operator ReferenceCountedObjectClass*() const { return referencedObject; } + + /** Returns the object that this pointer references. + The returned pointer may be null. + + @returns The pointee. + */ + ReferenceCountedObjectClass* operator->() const { return referencedObject; } + + /** Returns the object that this pointer references. + The returned pointer may be null. + + @returns The pointee. + */ + ReferenceCountedObjectClass* getObject() const { return referencedObject; } + +private: + //============================================================================== + ReferenceCountedObjectClass* referencedObject; +}; + +//============================================================================== + +// forward declaration +template +struct ContainerTraits; + +template +struct ContainerTraits> +{ + typedef T Type; + + static T* get(RefCountedObjectPtr const& c) { return c.getObject(); } +}; + +//============================================================================== + +} // namespace luabridge diff --git a/csgo2/LuaBridge/luaBridge/RefCountedPtr.h b/csgo2/LuaBridge/luaBridge/RefCountedPtr.h new file mode 100644 index 0000000..71de5c1 --- /dev/null +++ b/csgo2/LuaBridge/luaBridge/RefCountedPtr.h @@ -0,0 +1,226 @@ +// https://github.com/vinniefalco/LuaBridge +// Copyright 2021, Stefan Frings +// Copyright 2019, Dmitry Tarakanov +// Copyright 2012, Vinnie Falco +// Copyright 2007, Nathan Reed +// SPDX-License-Identifier: MIT + +#pragma once + +#include +#include +#include + +namespace luabridge { + +namespace detail { + +//============================================================================== +/** + Support for our RefCountedPtr. +*/ +struct RefCountedPtrBase +{ + // Declaration of container for the refcounts + typedef std::unordered_map RefCountsType; + +protected: + RefCountsType& getRefCounts() const + { + static RefCountsType refcounts; + return refcounts; + } +}; + +} // namespace detail + +//============================================================================== +/** + A reference counted smart pointer. + + The api is compatible with boost::RefCountedPtr and std::RefCountedPtr, in the + sense that it implements a strict subset of the functionality. + + This implementation uses a hash table to look up the reference count + associated with a particular pointer. + + @tparam T The class type. + + @todo Decompose RefCountedPtr using a policy. At a minimum, the underlying + reference count should be policy based (to support atomic operations) + and the delete behavior should be policy based (to support custom + disposal methods). + + @todo Provide an intrusive version of RefCountedPtr. +*/ +template +class RefCountedPtr : private detail::RefCountedPtrBase +{ +public: + template + struct rebind + { + typedef RefCountedPtr other; + }; + + /** Construct as nullptr or from existing pointer to T. + + @param p The optional, existing pointer to assign from. + */ + RefCountedPtr(T* const p = nullptr) : m_p(p) + { + if (m_p) + { + ++getRefCounts()[m_p]; + } + } + + /** Construct from another RefCountedPtr. + + @param rhs The RefCountedPtr to assign from. + */ + RefCountedPtr(RefCountedPtr const& rhs) : RefCountedPtr(rhs.get()) {} + + /** Construct from a RefCountedPtr of a different type. + + @invariant A pointer to U must be convertible to a pointer to T. + + @tparam U The other object type. + @param rhs The RefCountedPtr to assign from. + */ + template + RefCountedPtr(RefCountedPtr const& rhs) : RefCountedPtr(rhs.get()) + { + } + + /** Release the object. + + If there are no more references then the object is deleted. + */ + ~RefCountedPtr() { reset(); } + + /** Assign from another RefCountedPtr. + + @param rhs The RefCountedPtr to assign from. + @returns A reference to the RefCountedPtr. + */ + RefCountedPtr& operator=(RefCountedPtr const& rhs) + { + // NOTE Self assignment is handled gracefully + *this = rhs.get(); + return *this; + } + + /** Assign from another RefCountedPtr of a different type. + + @note A pointer to U must be convertible to a pointer to T. + + @tparam U The other object type. + @param rhs The other RefCountedPtr to assign from. + @returns A reference to the RefCountedPtr. + */ + template + RefCountedPtr& operator=(RefCountedPtr const& rhs) + { + // NOTE Self assignment is handled gracefully + *this = rhs.get(); + return *this; + } + + RefCountedPtr& operator=(T* const p) + { + if (p != m_p) + { + RefCountedPtr tmp(p); + std::swap(m_p, tmp.m_p); + } + + return *this; + } + + /** Retrieve the raw pointer. + + @returns A pointer to the object. + */ + T* get() const { return m_p; } + + /** Retrieve the raw pointer by conversion. + + @returns A pointer to the object. + */ + operator T*() const { return m_p; } + + /** Retrieve the raw pointer. + + @returns A pointer to the object. + */ + T* operator*() const { return m_p; } + + /** Retrieve the raw pointer. + + @returns A pointer to the object. + */ + T* operator->() const { return m_p; } + + /** Determine the number of references. + + @note This is not thread-safe. + + @returns The number of active references. + */ + RefCountsType::mapped_type use_count() const + { + if (!m_p) + { + return 0; + } + + const auto itCounter = getRefCounts().find(m_p); + assert(itCounter != getRefCounts().end()); + assert(itCounter->second > 0); + + return itCounter->second; + } + + /** Release the pointer. + + The reference count is decremented. If the reference count reaches + zero, the object is deleted. + */ + void reset() + { + if (m_p) + { + const auto itCounter = getRefCounts().find(m_p); + assert(itCounter != getRefCounts().end()); + assert(itCounter->second > 0); + + if (--itCounter->second == 0) + { + delete m_p; + getRefCounts().erase(itCounter); + } + + m_p = nullptr; + } + } + +private: + T* m_p; +}; + +//============================================================================== + +// forward declaration +template +struct ContainerTraits; + +template +struct ContainerTraits> +{ + typedef T Type; + + static T* get(RefCountedPtr const& c) { return c.get(); } +}; + +} // namespace luabridge diff --git a/csgo2/LuaBridge/luaBridge/UnorderedMap.h b/csgo2/LuaBridge/luaBridge/UnorderedMap.h new file mode 100644 index 0000000..80aa57c --- /dev/null +++ b/csgo2/LuaBridge/luaBridge/UnorderedMap.h @@ -0,0 +1,51 @@ +// https://github.com/vinniefalco/LuaBridge +// Copyright 2019, Dmitry Tarakanov +// SPDX-License-Identifier: MIT + +#pragma once + +#include + +#include + +namespace luabridge { + +template +struct Stack> +{ + typedef std::unordered_map Map; + + static void push(lua_State* L, const Map& map) + { + lua_createtable(L, 0, static_cast(map.size())); + typedef typename Map::const_iterator ConstIter; + for (ConstIter i = map.begin(); i != map.end(); ++i) + { + Stack::push(L, i->first); + Stack::push(L, i->second); + lua_settable(L, -3); + } + } + + static Map get(lua_State* L, int index) + { + if (!lua_istable(L, index)) + { + luaL_error(L, "#%d argument must be a table", index); + } + + Map map; + int const absindex = lua_absindex(L, index); + lua_pushnil(L); + while (lua_next(L, absindex) != 0) + { + map.emplace(Stack::get(L, -2), Stack::get(L, -1)); + lua_pop(L, 1); + } + return map; + } + + static bool isInstance(lua_State* L, int index) { return lua_istable(L, index); } +}; + +} // namespace luabridge diff --git a/csgo2/LuaBridge/luaBridge/Vector.h b/csgo2/LuaBridge/luaBridge/Vector.h new file mode 100644 index 0000000..1712f33 --- /dev/null +++ b/csgo2/LuaBridge/luaBridge/Vector.h @@ -0,0 +1,50 @@ +// https://github.com/vinniefalco/LuaBridge +// Copyright 2018, Dmitry Tarakanov +// SPDX-License-Identifier: MIT + +#pragma once + +#include + +#include + +namespace luabridge { + +template +struct Stack> +{ + static void push(lua_State* L, std::vector const& vector) + { + lua_createtable(L, static_cast(vector.size()), 0); + for (std::size_t i = 0; i < vector.size(); ++i) + { + lua_pushinteger(L, static_cast(i + 1)); + Stack::push(L, vector[i]); + lua_settable(L, -3); + } + } + + static std::vector get(lua_State* L, int index) + { + if (!lua_istable(L, index)) + { + luaL_error(L, "#%d argument must be a table", index); + } + + std::vector vector; + vector.reserve(static_cast(get_length(L, index))); + + int const absindex = lua_absindex(L, index); + lua_pushnil(L); + while (lua_next(L, absindex) != 0) + { + vector.push_back(Stack::get(L, -1)); + lua_pop(L, 1); + } + return vector; + } + + static bool isInstance(lua_State* L, int index) { return lua_istable(L, index); } +}; + +} // namespace luabridge diff --git a/csgo2/LuaBridge/luaBridge/detail/CFunctions.h b/csgo2/LuaBridge/luaBridge/detail/CFunctions.h new file mode 100644 index 0000000..7d58c07 --- /dev/null +++ b/csgo2/LuaBridge/luaBridge/detail/CFunctions.h @@ -0,0 +1,470 @@ +// https://github.com/vinniefalco/LuaBridge +// Copyright 2019, Dmitry Tarakanov +// Copyright 2012, Vinnie Falco +// SPDX-License-Identifier: MIT + +#pragma once + +#include +#include + +#include + +namespace luabridge { + +namespace detail { + +// We use a structure so we can define everything in the header. +// +struct CFunc +{ + static void addGetter(lua_State* L, const char* name, int tableIndex) + { + assert(lua_istable(L, tableIndex)); + assert(lua_iscfunction(L, -1)); // Stack: getter + + lua_rawgetp(L, tableIndex, getPropgetKey()); // Stack: getter, propget table (pg) + lua_pushvalue(L, -2); // Stack: getter, pg, getter + rawsetfield(L, -2, name); // Stack: getter, pg + lua_pop(L, 2); // Stack: - + } + + static void addSetter(lua_State* L, const char* name, int tableIndex) + { + assert(lua_istable(L, tableIndex)); + assert(lua_iscfunction(L, -1)); // Stack: setter + + lua_rawgetp(L, tableIndex, getPropsetKey()); // Stack: setter, propset table (ps) + lua_pushvalue(L, -2); // Stack: setter, ps, setter + rawsetfield(L, -2, name); // Stack: setter, ps + lua_pop(L, 2); // Stack: - + } + + //---------------------------------------------------------------------------- + /** + __index metamethod for a namespace or class static and non-static members. + Retrieves functions from metatables and properties from propget tables. + Looks through the class hierarchy if inheritance is present. + */ + static int indexMetaMethod(lua_State* L) + { + assert(lua_istable(L, 1) || + lua_isuserdata(L, 1)); // Stack (further not shown): table | userdata, name + + lua_getmetatable(L, 1); // Stack: class/const table (mt) + assert(lua_istable(L, -1)); + + for (;;) + { + lua_pushvalue(L, 2); // Stack: mt, field name + lua_rawget(L, -2); // Stack: mt, field | nil + + if (lua_iscfunction(L, -1)) // Stack: mt, field + { + lua_remove(L, -2); // Stack: field + return 1; + } + + assert(lua_isnil(L, -1)); // Stack: mt, nil + lua_pop(L, 1); // Stack: mt + + lua_rawgetp(L, -1, getPropgetKey()); // Stack: mt, propget table (pg) + assert(lua_istable(L, -1)); + + lua_pushvalue(L, 2); // Stack: mt, pg, field name + lua_rawget(L, -2); // Stack: mt, pg, getter | nil + lua_remove(L, -2); // Stack: mt, getter | nil + + if (lua_iscfunction(L, -1)) // Stack: mt, getter + { + lua_remove(L, -2); // Stack: getter + lua_pushvalue(L, 1); // Stack: getter, table | userdata + lua_call(L, 1, 1); // Stack: value + return 1; + } + + assert(lua_isnil(L, -1)); // Stack: mt, nil + lua_pop(L, 1); // Stack: mt + + // It may mean that the field may be in const table and it's constness violation. + // Don't check that, just return nil + + // Repeat the lookup in the parent metafield, + // or return nil if the field doesn't exist. + lua_rawgetp(L, -1, getParentKey()); // Stack: mt, parent mt | nil + + if (lua_isnil(L, -1)) // Stack: mt, nil + { + lua_remove(L, -2); // Stack: nil + return 1; + } + + // Removethe metatable and repeat the search in the parent one. + assert(lua_istable(L, -1)); // Stack: mt, parent mt + lua_remove(L, -2); // Stack: parent mt + } + + // no return + } + + //---------------------------------------------------------------------------- + /** + __newindex metamethod for namespace or class static members. + Retrieves properties from propset tables. + */ + static int newindexStaticMetaMethod(lua_State* L) { return newindexMetaMethod(L, false); } + + //---------------------------------------------------------------------------- + /** + __newindex metamethod for non-static members. + Retrieves properties from propset tables. + */ + static int newindexObjectMetaMethod(lua_State* L) { return newindexMetaMethod(L, true); } + + static int newindexMetaMethod(lua_State* L, bool pushSelf) + { + assert( + lua_istable(L, 1) || + lua_isuserdata(L, 1)); // Stack (further not shown): table | userdata, name, new value + + lua_getmetatable(L, 1); // Stack: metatable (mt) + assert(lua_istable(L, -1)); + + for (;;) + { + lua_rawgetp(L, -1, getPropsetKey()); // Stack: mt, propset table (ps) | nil + + if (lua_isnil(L, -1)) // Stack: mt, nil + { + lua_pop(L, 2); // Stack: - + return luaL_error(L, "No member named '%s'", lua_tostring(L, 2)); + } + + assert(lua_istable(L, -1)); + + lua_pushvalue(L, 2); // Stack: mt, ps, field name + lua_rawget(L, -2); // Stack: mt, ps, setter | nil + lua_remove(L, -2); // Stack: mt, setter | nil + + if (lua_iscfunction(L, -1)) // Stack: mt, setter + { + lua_remove(L, -2); // Stack: setter + if (pushSelf) + { + lua_pushvalue(L, 1); // Stack: setter, table | userdata + } + lua_pushvalue(L, 3); // Stack: setter, table | userdata, new value + lua_call(L, pushSelf ? 2 : 1, 0); // Stack: - + return 0; + } + + assert(lua_isnil(L, -1)); // Stack: mt, nil + lua_pop(L, 1); // Stack: mt + + lua_rawgetp(L, -1, getParentKey()); // Stack: mt, parent mt | nil + + if (lua_isnil(L, -1)) // Stack: mt, nil + { + lua_pop(L, 1); // Stack: - + return luaL_error(L, "No writable member '%s'", lua_tostring(L, 2)); + } + + assert(lua_istable(L, -1)); // Stack: mt, parent mt + lua_remove(L, -2); // Stack: parent mt + // Repeat the search in the parent + } + + // no return + } + + //---------------------------------------------------------------------------- + /** + lua_CFunction to report an error writing to a read-only value. + + The name of the variable is in the first upvalue. + */ + static int readOnlyError(lua_State* L) + { + std::string s; + + s = s + "'" + lua_tostring(L, lua_upvalueindex(1)) + "' is read-only"; + + return luaL_error(L, s.c_str()); + } + + //---------------------------------------------------------------------------- + /** + lua_CFunction to get a variable. + + This is used for global variables or class static data members. + + The pointer to the data is in the first upvalue. + */ + template + static int getVariable(lua_State* L) + { + assert(lua_islightuserdata(L, lua_upvalueindex(1))); + T const* ptr = static_cast(lua_touserdata(L, lua_upvalueindex(1))); + assert(ptr != 0); + Stack::push(L, *ptr); + return 1; + } + + //---------------------------------------------------------------------------- + /** + lua_CFunction to set a variable. + + This is used for global variables or class static data members. + + The pointer to the data is in the first upvalue. + */ + template + static int setVariable(lua_State* L) + { + assert(lua_islightuserdata(L, lua_upvalueindex(1))); + T* ptr = static_cast(lua_touserdata(L, lua_upvalueindex(1))); + assert(ptr != 0); + *ptr = Stack::get(L, 1); + return 0; + } + + //---------------------------------------------------------------------------- + /** + lua_CFunction to call a function with a return value. + + This is used for global functions, global properties, class static methods, + and class static properties. + + The function pointer (lightuserdata) in the first upvalue. + */ + template + struct Call + { + typedef typename FuncTraits::Params Params; + typedef typename FuncTraits::ReturnType ReturnType; + + static int f(lua_State* L) + { + assert(lua_islightuserdata(L, lua_upvalueindex(1))); + FnPtr fnptr = reinterpret_cast(lua_touserdata(L, lua_upvalueindex(1))); + assert(fnptr != 0); + return Invoke::run(L, fnptr); + } + }; + + //---------------------------------------------------------------------------- + /** + lua_CFunction to call a class member function with a return value. + + The member function pointer is in the first upvalue. + The class userdata object is at the top of the Lua stack. + */ + template + struct CallMember + { + typedef typename FuncTraits::ClassType T; + typedef typename FuncTraits::Params Params; + typedef typename FuncTraits::ReturnType ReturnType; + + static int f(lua_State* L) + { + assert(isfulluserdata(L, lua_upvalueindex(1))); + T* const t = Userdata::get(L, 1, false); + MemFnPtr const& fnptr = + *static_cast(lua_touserdata(L, lua_upvalueindex(1))); + assert(fnptr != 0); + return Invoke::run(L, t, fnptr); + } + }; + + template + struct CallConstMember + { + typedef typename FuncTraits::ClassType T; + typedef typename FuncTraits::Params Params; + typedef typename FuncTraits::ReturnType ReturnType; + + static int f(lua_State* L) + { + assert(isfulluserdata(L, lua_upvalueindex(1))); + T const* const t = Userdata::get(L, 1, true); + MemFnPtr const& fnptr = + *static_cast(lua_touserdata(L, lua_upvalueindex(1))); + assert(fnptr != 0); + return Invoke::run(L, t, fnptr); + } + }; + + //-------------------------------------------------------------------------- + /** + lua_CFunction to call a class member lua_CFunction. + + The member function pointer is in the first upvalue. + The object userdata ('this') value is at top ot the Lua stack. + */ + template + struct CallMemberCFunction + { + static int f(lua_State* L) + { + assert(isfulluserdata(L, lua_upvalueindex(1))); + typedef int (T::*MFP)(lua_State * L); + T* const t = Userdata::get(L, 1, false); + MFP const& fnptr = *static_cast(lua_touserdata(L, lua_upvalueindex(1))); + assert(fnptr != 0); + return (t->*fnptr)(L); + } + }; + + template + struct CallConstMemberCFunction + { + static int f(lua_State* L) + { + assert(isfulluserdata(L, lua_upvalueindex(1))); + typedef int (T::*MFP)(lua_State * L); + T const* const t = Userdata::get(L, 1, true); + MFP const& fnptr = *static_cast(lua_touserdata(L, lua_upvalueindex(1))); + assert(fnptr != 0); + return (t->*fnptr)(L); + } + }; + + //-------------------------------------------------------------------------- + /** + lua_CFunction to call on a object. + + The proxy function pointer (lightuserdata) is in the first upvalue. + The class userdata object is at the top of the Lua stack. + */ + template + struct CallProxyFunction + { + using Params = typename FuncTraits::Params; + using ReturnType = typename FuncTraits::ReturnType; + + static int f(lua_State* L) + { + assert(lua_islightuserdata(L, lua_upvalueindex(1))); + auto fnptr = reinterpret_cast(lua_touserdata(L, lua_upvalueindex(1))); + assert(fnptr != 0); + return Invoke::run(L, fnptr); + } + }; + + template + struct CallProxyFunctor + { + using Params = typename FuncTraits::Params; + using ReturnType = typename FuncTraits::ReturnType; + + static int f(lua_State* L) + { + assert(isfulluserdata(L, lua_upvalueindex(1))); + Functor& fn = *static_cast(lua_touserdata(L, lua_upvalueindex(1))); + return Invoke::run(L, fn); + } + }; + + //-------------------------------------------------------------------------- + + // SFINAE Helpers + + template + struct CallMemberFunctionHelper + { + static void add(lua_State* L, char const* name, MemFnPtr mf) + { + new (lua_newuserdata(L, sizeof(MemFnPtr))) MemFnPtr(mf); + lua_pushcclosure(L, &CallConstMember::f, 1); + lua_pushvalue(L, -1); + rawsetfield(L, -5, name); // const table + rawsetfield(L, -3, name); // class table + } + }; + + template + struct CallMemberFunctionHelper + { + static void add(lua_State* L, char const* name, MemFnPtr mf) + { + new (lua_newuserdata(L, sizeof(MemFnPtr))) MemFnPtr(mf); + lua_pushcclosure(L, &CallMember::f, 1); + rawsetfield(L, -3, name); // class table + } + }; + + //-------------------------------------------------------------------------- + /** + __gc metamethod for a class. + */ + template + static int gcMetaMethod(lua_State* L) + { + Userdata* const ud = Userdata::getExact(L, 1); + ud->~Userdata(); + return 0; + } + + /** + __gc metamethod for an arbitrary class. + */ + template + static int gcMetaMethodAny(lua_State* L) + { + assert(isfulluserdata(L, 1)); + T* t = static_cast(lua_touserdata(L, 1)); + t->~T(); + return 0; + } + + //-------------------------------------------------------------------------- + /** + lua_CFunction to get a class data member. + + The pointer-to-member is in the first upvalue. + The class userdata object is at the top of the Lua stack. + */ + template + static int getProperty(lua_State* L) + { + C* const c = Userdata::get(L, 1, true); + T C::** mp = static_cast(lua_touserdata(L, lua_upvalueindex(1))); + try + { + Stack::push(L, c->**mp); + } + catch (const std::exception& e) + { + luaL_error(L, e.what()); + } + return 1; + } + + //-------------------------------------------------------------------------- + /** + lua_CFunction to set a class data member. + + The pointer-to-member is in the first upvalue. + The class userdata object is at the top of the Lua stack. + */ + template + static int setProperty(lua_State* L) + { + C* const c = Userdata::get(L, 1, false); + T C::** mp = static_cast(lua_touserdata(L, lua_upvalueindex(1))); + try + { + c->** mp = Stack::get(L, 2); + } + catch (const std::exception& e) + { + luaL_error(L, e.what()); + } + return 0; + } +}; + +} // namespace detail + +} // namespace luabridge diff --git a/csgo2/LuaBridge/luaBridge/detail/ClassInfo.h b/csgo2/LuaBridge/luaBridge/detail/ClassInfo.h new file mode 100644 index 0000000..90c3a3c --- /dev/null +++ b/csgo2/LuaBridge/luaBridge/detail/ClassInfo.h @@ -0,0 +1,140 @@ +// https://github.com/vinniefalco/LuaBridge +// Copyright 2020, Dmitry Tarakanov +// Copyright 2012, Vinnie Falco +// SPDX-License-Identifier: MIT + +#pragma once + +namespace luabridge { + +namespace detail { + +/** + * A unique key for a type name in a metatable. + */ +inline const void* getTypeKey() +{ +#ifdef _NDEBUG + static char value; + return &value; +#else + return reinterpret_cast(0x71); +#endif +} + +/** + * The key of a const table in another metatable. + */ +inline const void* getConstKey() +{ +#ifdef _NDEBUG + static char value; + return &value; +#else + return reinterpret_cast(0xc07); +#endif +} + +/** + * The key of a class table in another metatable. + */ +inline const void* getClassKey() +{ +#ifdef _NDEBUG + static char value; + return &value; +#else + return reinterpret_cast(0xc1a); +#endif +} + +/** + * The key of a propget table in another metatable. + */ +inline const void* getPropgetKey() +{ +#ifdef _NDEBUG + static char value; + return &value; +#else + return reinterpret_cast(0x6e7); +#endif +} + +/** + * The key of a propset table in another metatable. + */ +inline const void* getPropsetKey() +{ +#ifdef _NDEBUG + static char value; + return &value; +#else + return reinterpret_cast(0x5e7); +#endif +} + +/** + * The key of a static table in another metatable. + */ +inline const void* getStaticKey() +{ +#ifdef _NDEBUG + static char value; + return &value; +#else + return reinterpret_cast(0x57a); +#endif +} + +/** + * The key of a parent table in another metatable. + */ +inline const void* getParentKey() +{ +#ifdef _NDEBUG + static char value; + return &value; +#else + return reinterpret_cast(0xdad); +#endif +} + +/** + Get the key for the static table in the Lua registry. + The static table holds the static data members, static properties, and + static member functions for a class. +*/ +template +void const* getStaticRegistryKey() +{ + static char value; + return &value; +} + +/** Get the key for the class table in the Lua registry. + The class table holds the data members, properties, and member functions + of a class. Read-only data and properties, and const member functions are + also placed here (to save a lookup in the const table). +*/ +template +void const* getClassRegistryKey() +{ + static char value; + return &value; +} + +/** Get the key for the const table in the Lua registry. + The const table holds read-only data members and properties, and const + member functions of a class. +*/ +template +void const* getConstRegistryKey() +{ + static char value; + return &value; +} + +} // namespace detail + +} // namespace luabridge diff --git a/csgo2/LuaBridge/luaBridge/detail/Config.h b/csgo2/LuaBridge/luaBridge/detail/Config.h new file mode 100644 index 0000000..2cf8064 --- /dev/null +++ b/csgo2/LuaBridge/luaBridge/detail/Config.h @@ -0,0 +1,7 @@ +// https://github.com/vinniefalco/LuaBridge +// Copyright 2020, Dmitry Tarakanov +// SPDX-License-Identifier: MIT + +#pragma once + +// Empty file diff --git a/csgo2/LuaBridge/luaBridge/detail/Constructor.h b/csgo2/LuaBridge/luaBridge/detail/Constructor.h new file mode 100644 index 0000000..f3e72d7 --- /dev/null +++ b/csgo2/LuaBridge/luaBridge/detail/Constructor.h @@ -0,0 +1,225 @@ +// https://github.com/vinniefalco/LuaBridge +// Copyright 2012, Vinnie Falco +// Copyright 2007, Nathan Reed +// SPDX-License-Identifier: MIT + +#pragma once + +namespace luabridge { + +namespace detail { + +/* + * Constructor generators. These templates allow you to call operator new and + * pass the contents of a type/value list to the Constructor. Like the + * function pointer containers, these are only defined up to 8 parameters. + */ + +/** Constructor generators. + + These templates call operator new with the contents of a type/value + list passed to the Constructor with up to 8 parameters. Two versions + of call() are provided. One performs a regular new, the other performs + a placement new. +*/ +template +struct Constructor +{ +}; + +template +struct Constructor +{ + static T* call(TypeListValues const&) { return new T; } + static T* call(void* mem, TypeListValues const&) { return new (mem) T; } +}; + +template +struct Constructor> +{ + static T* call(const TypeListValues>& tvl) { return new T(tvl.hd); } + static T* call(void* mem, const TypeListValues>& tvl) + { + return new (mem) T(tvl.hd); + } +}; + +template +struct Constructor>> +{ + static T* call(const TypeListValues>>& tvl) + { + return new T(tvl.hd, tvl.tl.hd); + } + static T* call(void* mem, const TypeListValues>>& tvl) + { + return new (mem) T(tvl.hd, tvl.tl.hd); + } +}; + +template +struct Constructor>>> +{ + static T* call(const TypeListValues>>>& tvl) + { + return new T(tvl.hd, tvl.tl.hd, tvl.tl.tl.hd); + } + static T* call(void* mem, const TypeListValues>>>& tvl) + { + return new (mem) T(tvl.hd, tvl.tl.hd, tvl.tl.tl.hd); + } +}; + +template +struct Constructor>>>> +{ + static T* + call(const TypeListValues>>>>& tvl) + { + return new T(tvl.hd, tvl.tl.hd, tvl.tl.tl.hd, tvl.tl.tl.tl.hd); + } + static T* + call(void* mem, + const TypeListValues>>>>& tvl) + { + return new (mem) T(tvl.hd, tvl.tl.hd, tvl.tl.tl.hd, tvl.tl.tl.tl.hd); + } +}; + +template +struct Constructor>>>>> +{ + static T* + call(const TypeListValues>>>>>& + tvl) + { + return new T(tvl.hd, tvl.tl.hd, tvl.tl.tl.hd, tvl.tl.tl.tl.hd, tvl.tl.tl.tl.tl.hd); + } + static T* + call(void* mem, + const TypeListValues>>>>>& + tvl) + { + return new (mem) T(tvl.hd, tvl.tl.hd, tvl.tl.tl.hd, tvl.tl.tl.tl.hd, tvl.tl.tl.tl.tl.hd); + } +}; + +template +struct Constructor< + T, + TypeList>>>>>> +{ + static T* + call(const TypeListValues< + TypeList>>>>>>& tvl) + { + return new T(tvl.hd, + tvl.tl.hd, + tvl.tl.tl.hd, + tvl.tl.tl.tl.hd, + tvl.tl.tl.tl.tl.hd, + tvl.tl.tl.tl.tl.tl.hd); + } + static T* + call(void* mem, + const TypeListValues< + TypeList>>>>>>& + tvl) + { + return new (mem) T(tvl.hd, + tvl.tl.hd, + tvl.tl.tl.hd, + tvl.tl.tl.tl.hd, + tvl.tl.tl.tl.tl.hd, + tvl.tl.tl.tl.tl.tl.hd); + } +}; + +template +struct Constructor< + T, + TypeList>>>>>>> +{ + static T* + call(const TypeListValues>>>>>>>& + tvl) + { + return new T(tvl.hd, + tvl.tl.hd, + tvl.tl.tl.hd, + tvl.tl.tl.tl.hd, + tvl.tl.tl.tl.tl.hd, + tvl.tl.tl.tl.tl.tl.hd, + tvl.tl.tl.tl.tl.tl.tl.hd); + } + static T* + call(void* mem, + const TypeListValues>>>>>>>& + tvl) + { + return new (mem) T(tvl.hd, + tvl.tl.hd, + tvl.tl.tl.hd, + tvl.tl.tl.tl.hd, + tvl.tl.tl.tl.tl.hd, + tvl.tl.tl.tl.tl.tl.hd, + tvl.tl.tl.tl.tl.tl.tl.hd); + } +}; + +template +struct Constructor< + T, + TypeList< + P1, + TypeList< + P2, + TypeList>>>>>>>> +{ + static T* + call(const TypeListValues>>>>>>>>& + tvl) + { + return new T(tvl.hd, + tvl.tl.hd, + tvl.tl.tl.hd, + tvl.tl.tl.tl.hd, + tvl.tl.tl.tl.tl.hd, + tvl.tl.tl.tl.tl.tl.hd, + tvl.tl.tl.tl.tl.tl.tl.hd, + tvl.tl.tl.tl.tl.tl.tl.tl.hd); + } + static T* + call(void* mem, + const TypeListValues>>>>>>>>& + tvl) + { + return new (mem) T(tvl.hd, + tvl.tl.hd, + tvl.tl.tl.hd, + tvl.tl.tl.tl.hd, + tvl.tl.tl.tl.tl.hd, + tvl.tl.tl.tl.tl.tl.hd, + tvl.tl.tl.tl.tl.tl.tl.hd, + tvl.tl.tl.tl.tl.tl.tl.tl.hd); + } +}; + +} // namespace detail + +} // namespace luabridge diff --git a/csgo2/LuaBridge/luaBridge/detail/FuncTraits.h b/csgo2/LuaBridge/luaBridge/detail/FuncTraits.h new file mode 100644 index 0000000..1db7169 --- /dev/null +++ b/csgo2/LuaBridge/luaBridge/detail/FuncTraits.h @@ -0,0 +1,435 @@ +// https://github.com/vinniefalco/LuaBridge +// Copyright 2020, Dmitry Tarakanov +// Copyright 2012, Vinnie Falco +// SPDX-License-Identifier: MIT + +#pragma once + +#include +#include + +#include + +namespace luabridge { + +namespace detail { + +/** + Since the throw specification is part of a function signature, the FuncTraits + family of templates needs to be specialized for both types. The + LUABRIDGE_THROWSPEC macro controls whether we use the 'throw ()' form, or + 'noexcept' (if C++11 is available) to distinguish the functions. +*/ +#if defined(__APPLE_CPP__) || defined(__APPLE_CC__) || defined(__clang__) || defined(__GNUC__) || \ + (defined(_MSC_VER) && (_MSC_VER >= 1700)) +// Do not define LUABRIDGE_THROWSPEC since the Xcode and gcc compilers do not +// distinguish the throw specification in the function signature. +#define LUABRIDGE_THROWSPEC +#else +// Visual Studio 10 and earlier pay too much mind to useless throw () spec. +// +#define LUABRIDGE_THROWSPEC throw() +#endif + +//============================================================================== +/** + * Traits class for unrolling the type list values into function arguments. + */ +template +struct Caller; + +template +struct Caller +{ + template + static ReturnType f(Fn& fn, TypeListValues&) + { + return fn(); + } + + template + static ReturnType f(T* obj, MemFn& fn, TypeListValues&) + { + return (obj->*fn)(); + } +}; + +template +struct Caller +{ + template + static ReturnType f(Fn& fn, TypeListValues& tvl) + { + return fn(tvl.hd); + } + + template + static ReturnType f(T* obj, MemFn& fn, TypeListValues& tvl) + { + return (obj->*fn)(tvl.hd); + } +}; + +template +struct Caller +{ + template + static ReturnType f(Fn& fn, TypeListValues& tvl) + { + return fn(tvl.hd, tvl.tl.hd); + } + + template + static ReturnType f(T* obj, MemFn& fn, TypeListValues& tvl) + { + return (obj->*fn)(tvl.hd, tvl.tl.hd); + } +}; + +template +struct Caller +{ + template + static ReturnType f(Fn& fn, TypeListValues& tvl) + { + return fn(tvl.hd, tvl.tl.hd, tvl.tl.tl.hd); + } + + template + static ReturnType f(T* obj, MemFn& fn, TypeListValues& tvl) + { + return (obj->*fn)(tvl.hd, tvl.tl.hd, tvl.tl.tl.hd); + } +}; + +template +struct Caller +{ + template + static ReturnType f(Fn& fn, TypeListValues& tvl) + { + return fn(tvl.hd, tvl.tl.hd, tvl.tl.tl.hd, tvl.tl.tl.tl.hd); + } + + template + static ReturnType f(T* obj, MemFn& fn, TypeListValues& tvl) + { + return (obj->*fn)(tvl.hd, tvl.tl.hd, tvl.tl.tl.hd, tvl.tl.tl.tl.hd); + } +}; + +template +struct Caller +{ + template + static ReturnType f(Fn& fn, TypeListValues& tvl) + { + return fn(tvl.hd, tvl.tl.hd, tvl.tl.tl.hd, tvl.tl.tl.tl.hd, tvl.tl.tl.tl.tl.hd); + } + + template + static ReturnType f(T* obj, MemFn& fn, TypeListValues& tvl) + { + return (obj->*fn)(tvl.hd, tvl.tl.hd, tvl.tl.tl.hd, tvl.tl.tl.tl.hd, tvl.tl.tl.tl.tl.hd); + } +}; + +template +struct Caller +{ + template + static ReturnType f(Fn& fn, TypeListValues& tvl) + { + return fn(tvl.hd, + tvl.tl.hd, + tvl.tl.tl.hd, + tvl.tl.tl.tl.hd, + tvl.tl.tl.tl.tl.hd, + tvl.tl.tl.tl.tl.tl.hd); + } + + template + static ReturnType f(T* obj, MemFn& fn, TypeListValues& tvl) + { + return (obj->*fn)(tvl.hd, + tvl.tl.hd, + tvl.tl.tl.hd, + tvl.tl.tl.tl.hd, + tvl.tl.tl.tl.tl.hd, + tvl.tl.tl.tl.tl.tl.hd); + } +}; + +template +struct Caller +{ + template + static ReturnType f(Fn& fn, TypeListValues& tvl) + { + return fn(tvl.hd, + tvl.tl.hd, + tvl.tl.tl.hd, + tvl.tl.tl.tl.hd, + tvl.tl.tl.tl.tl.hd, + tvl.tl.tl.tl.tl.tl.hd, + tvl.tl.tl.tl.tl.tl.tl.hd); + } + + template + static ReturnType f(T* obj, MemFn& fn, TypeListValues& tvl) + { + return (obj->*fn)(tvl.hd, + tvl.tl.hd, + tvl.tl.tl.hd, + tvl.tl.tl.tl.hd, + tvl.tl.tl.tl.tl.hd, + tvl.tl.tl.tl.tl.tl.hd, + tvl.tl.tl.tl.tl.tl.tl.hd); + } +}; + +template +struct Caller +{ + template + static ReturnType f(Fn& fn, TypeListValues& tvl) + { + return fn(tvl.hd, + tvl.tl.hd, + tvl.tl.tl.hd, + tvl.tl.tl.tl.hd, + tvl.tl.tl.tl.tl.hd, + tvl.tl.tl.tl.tl.tl.hd, + tvl.tl.tl.tl.tl.tl.tl.hd, + tvl.tl.tl.tl.tl.tl.tl.tl.hd); + } + + template + static ReturnType f(T* obj, MemFn& fn, TypeListValues& tvl) + { + return (obj->*fn)(tvl.hd, + tvl.tl.hd, + tvl.tl.tl.hd, + tvl.tl.tl.tl.hd, + tvl.tl.tl.tl.tl.hd, + tvl.tl.tl.tl.tl.tl.hd, + tvl.tl.tl.tl.tl.tl.tl.hd, + tvl.tl.tl.tl.tl.tl.tl.tl.hd); + } +}; + +template +struct Caller +{ + template + static ReturnType f(Fn& fn, TypeListValues& tvl) + { + return fn(tvl.hd, + tvl.tl.hd, + tvl.tl.tl.hd, + tvl.tl.tl.tl.hd, + tvl.tl.tl.tl.tl.hd, + tvl.tl.tl.tl.tl.tl.hd, + tvl.tl.tl.tl.tl.tl.tl.hd, + tvl.tl.tl.tl.tl.tl.tl.tl.hd, + tvl.tl.tl.tl.tl.tl.tl.tl.tl.hd); + } + + template + static ReturnType f(T* obj, MemFn& fn, TypeListValues& tvl) + { + return (obj->*fn)(tvl.hd, + tvl.tl.hd, + tvl.tl.tl.hd, + tvl.tl.tl.tl.hd, + tvl.tl.tl.tl.tl.hd, + tvl.tl.tl.tl.tl.tl.hd, + tvl.tl.tl.tl.tl.tl.tl.hd, + tvl.tl.tl.tl.tl.tl.tl.tl.hd, + tvl.tl.tl.tl.tl.tl.tl.tl.tl.hd); + } +}; + +template +ReturnType doCall(Fn& fn, TypeListValues& tvl) +{ + return Caller::value>::f(fn, tvl); +} + +template +ReturnType doCall(T* obj, MemFn& fn, TypeListValues& tvl) +{ + return Caller::value>::f(obj, fn, tvl); +} + +//============================================================================== +/** + Traits for function pointers. + + There are three types of functions: global, non-const member, and const + member. These templates determine the type of function, which class type it + belongs to if it is a class member, the const-ness if it is a member + function, and the type information for the return value and argument list. + + Expansions are provided for functions with up to 8 parameters. This can be + manually extended, or expanded to an arbitrary amount using C++11 features. +*/ +template +struct FuncTraits +{ +}; + +/* Ordinary function pointers. */ + +template +struct FuncTraits +{ + static bool const isMemberFunction = false; + using DeclType = R (*)(ParamList...); + using ReturnType = R; + using Params = typename MakeTypeList::Result; + + static R call(const DeclType& fp, TypeListValues& tvl) { return doCall(fp, tvl); } +}; + +/* Windows: WINAPI (a.k.a. __stdcall) function pointers. */ + +#ifdef _M_IX86 // Windows 32bit only + +template +struct FuncTraits +{ + static bool const isMemberFunction = false; + using DeclType = R(__stdcall*)(ParamList...); + using ReturnType = R; + using Params = typename MakeTypeList::Result; + + static R call(const DeclType& fp, TypeListValues& tvl) { return doCall(fp, tvl); } +}; + +#endif // _M_IX86 + +/* Non-const member function pointers. */ + +template +struct FuncTraits +{ + static bool const isMemberFunction = true; + static bool const isConstMemberFunction = false; + using DeclType = R (T::*)(ParamList...); + using ClassType = T; + using ReturnType = R; + using Params = typename MakeTypeList::Result; + + static R call(ClassType* obj, const DeclType& fp, TypeListValues& tvl) + { + return doCall(obj, fp, tvl); + } +}; + +/* Const member function pointers. */ + +template +struct FuncTraits +{ + static bool const isMemberFunction = true; + static bool const isConstMemberFunction = true; + using DeclType = R (T::*)(ParamList...) const; + using ClassType = T; + using ReturnType = R; + using Params = typename MakeTypeList::Result; + + static R call(const ClassType* obj, const DeclType& fp, TypeListValues& tvl) + { + return doCall(obj, fp, tvl); + } +}; + +/* std::function */ + +template +struct FuncTraits> +{ + static bool const isMemberFunction = false; + static bool const isConstMemberFunction = false; + using DeclType = std::function; + using ReturnType = R; + using Params = typename MakeTypeList::Result; + + static ReturnType call(DeclType& fn, TypeListValues& tvl) + { + return doCall(fn, tvl); + } +}; + +template +struct Invoke +{ + template + static int run(lua_State* L, Fn& fn) + { + try + { + ArgList args(L); + Stack::push(L, FuncTraits::call(fn, args)); + return 1; + } + catch (const std::exception& e) + { + return luaL_error(L, e.what()); + } + } + + template + static int run(lua_State* L, T* object, const MemFn& fn) + { + try + { + ArgList args(L); + Stack::push(L, FuncTraits::call(object, fn, args)); + return 1; + } + catch (const std::exception& e) + { + return luaL_error(L, e.what()); + } + } +}; + +template +struct Invoke +{ + template + static int run(lua_State* L, Fn& fn) + { + try + { + ArgList args(L); + FuncTraits::call(fn, args); + return 0; + } + catch (const std::exception& e) + { + return luaL_error(L, e.what()); + } + } + + template + static int run(lua_State* L, T* object, const MemFn& fn) + { + try + { + ArgList args(L); + FuncTraits::call(object, fn, args); + return 0; + } + catch (const std::exception& e) + { + return luaL_error(L, e.what()); + } + } +}; + +} // namespace detail + +} // namespace luabridge diff --git a/csgo2/LuaBridge/luaBridge/detail/Iterator.h b/csgo2/LuaBridge/luaBridge/detail/Iterator.h new file mode 100644 index 0000000..45cfaec --- /dev/null +++ b/csgo2/LuaBridge/luaBridge/detail/Iterator.h @@ -0,0 +1,150 @@ +// https://github.com/vinniefalco/LuaBridge +// Copyright 2018, Dmitry Tarakanov +// Copyright 2012, Vinnie Falco +// SPDX-License-Identifier: MIT + +#pragma once + +#include + +#include + +namespace luabridge { + +/** Allows table iteration. + */ +class Iterator +{ + lua_State* m_L; + LuaRef m_table; + LuaRef m_key; + LuaRef m_value; + + void next() + { + m_table.push(); + m_key.push(); + if (lua_next(m_L, -2)) + { + m_value.pop(); + m_key.pop(); + } + else + { + m_key = Nil(); + m_value = Nil(); + } + lua_pop(m_L, 1); + } + +public: + explicit Iterator(const LuaRef& table, bool isEnd = false) + : m_L(table.state()) + , m_table(table) + , m_key(table.state()) // m_key is nil + , m_value(table.state()) // m_value is nil + { + if (!isEnd) + { + next(); // get the first (key, value) pair from table + } + } + + /// Return an associated Lua state. + /// + /// @returns A Lua state. + /// + lua_State* state() const { return m_L; } + + /// Dereference the iterator. + /// + /// @returns A key-value pair for a current table entry. + /// + std::pair operator*() const { return std::make_pair(m_key, m_value); } + + /// Return the value referred by the iterator. + /// + /// @returns A value for the current table entry. + /// + LuaRef operator->() const { return m_value; } + + /// Compare two iterators. + /// + /// @param rhs Another iterator. + /// @returns True if iterators point to the same entry of the same table, + /// false otherwise. + /// + bool operator!=(const Iterator& rhs) const + { + assert(m_L == rhs.m_L); + return !m_table.rawequal(rhs.m_table) || !m_key.rawequal(rhs.m_key); + } + + /// Move the iterator to the next table entry. + /// + /// @returns This iterator. + /// + Iterator& operator++() + { + if (isNil()) + { + // if the iterator reaches the end, do nothing + return *this; + } + else + { + next(); + return *this; + } + } + + /// Check if the iterator points after the last table entry. + /// + /// @returns True if there are no more table entries to iterate, + /// false otherwise. + /// + bool isNil() const { return m_key.isNil(); } + + /// Return the key for the current table entry. + /// + /// @returns A reference to the entry key. + /// + LuaRef key() const { return m_key; } + + /// Return the key for the current table entry. + /// + /// @returns A reference to the entry value. + /// + LuaRef value() const { return m_value; } + +private: + // Don't use postfix increment, it is less efficient + Iterator operator++(int); +}; + +namespace detail { + +class Range +{ + Iterator m_begin; + Iterator m_end; + +public: + Range(const Iterator& begin, const Iterator& end) : m_begin(begin), m_end(end) {} + + const Iterator& begin() const { return m_begin; } + const Iterator& end() const { return m_end; } +}; + +} // namespace detail + +/// Return a range for the Lua table reference. +/// +/// @returns A range suitable for range-based for statement. +/// +inline detail::Range pairs(const LuaRef& table) +{ + return detail::Range(Iterator(table, false), Iterator(table, true)); +} + +} // namespace luabridge diff --git a/csgo2/LuaBridge/luaBridge/detail/LuaException.h b/csgo2/LuaBridge/luaBridge/detail/LuaException.h new file mode 100644 index 0000000..75d9e25 --- /dev/null +++ b/csgo2/LuaBridge/luaBridge/detail/LuaException.h @@ -0,0 +1,104 @@ +// https://github.com/vinniefalco/LuaBridge +// Copyright 2012, Vinnie Falco +// Copyright 2008, Nigel Atkinson +// SPDX-License-Identifier: MIT + +#pragma once + +#include +#include + +namespace luabridge { + +class LuaException : public std::exception +{ +private: + lua_State* m_L; + std::string m_what; + +public: + //---------------------------------------------------------------------------- + /** + Construct a LuaException after a lua_pcall(). + */ + LuaException(lua_State* L, int /*code*/) : m_L(L) { whatFromStack(); } + + //---------------------------------------------------------------------------- + + LuaException(lua_State* L, char const*, char const*, long) : m_L(L) { whatFromStack(); } + + //---------------------------------------------------------------------------- + + ~LuaException() throw() {} + + //---------------------------------------------------------------------------- + + char const* what() const throw() { return m_what.c_str(); } + + //============================================================================ + /** + Throw an exception. + + This centralizes all the exceptions thrown, so that we can set + breakpoints before the stack is unwound, or otherwise customize the + behavior. + */ + template + static void Throw(Exception e) + { + throw e; + } + + //---------------------------------------------------------------------------- + /** + Wrapper for lua_pcall that throws. + */ + static void pcall(lua_State* L, int nargs = 0, int nresults = 0, int msgh = 0) + { + int code = lua_pcall(L, nargs, nresults, msgh); + + if (code != LUABRIDGE_LUA_OK) + Throw(LuaException(L, code)); + } + + //---------------------------------------------------------------------------- + /** + Initializes error handling. Subsequent Lua errors are translated to C++ exceptions. + */ + static void enableExceptions(lua_State* L) { lua_atpanic(L, throwAtPanic); } + + /** Retrieve the lua_State associated with the exception. + + @returns A Lua state. + */ + lua_State* state() const { return m_L; } + +protected: + void whatFromStack() + { + if (lua_gettop(m_L) > 0) + { + char const* s = lua_tostring(m_L, -1); + m_what = s ? s : ""; + } + else + { + // stack is empty + m_what = "missing error"; + } + } + +private: + static int throwAtPanic(lua_State* L) { throw LuaException(L, -1); } +}; + +//---------------------------------------------------------------------------- +/** + Initializes error handling. Subsequent Lua errors are translated to C++ exceptions. +*/ +static void enableExceptions(lua_State* L) +{ + LuaException::enableExceptions(L); +} + +} // namespace luabridge diff --git a/csgo2/LuaBridge/luaBridge/detail/LuaHelpers.h b/csgo2/LuaBridge/luaBridge/detail/LuaHelpers.h new file mode 100644 index 0000000..079fc7b --- /dev/null +++ b/csgo2/LuaBridge/luaBridge/detail/LuaHelpers.h @@ -0,0 +1,126 @@ +// https://github.com/vinniefalco/LuaBridge +// Copyright 2012, Vinnie Falco +// Copyright 2007, Nathan Reed +// SPDX-License-Identifier: MIT + +#pragma once + +#include + +namespace luabridge { + +// These are for Lua versions prior to 5.2.0. +// +#if LUA_VERSION_NUM < 502 +inline int lua_absindex(lua_State* L, int idx) +{ + if (idx > LUA_REGISTRYINDEX && idx < 0) + return lua_gettop(L) + idx + 1; + else + return idx; +} + +inline void lua_rawgetp(lua_State* L, int idx, void const* p) +{ + idx = lua_absindex(L, idx); + lua_pushlightuserdata(L, const_cast(p)); + lua_rawget(L, idx); +} + +inline void lua_rawsetp(lua_State* L, int idx, void const* p) +{ + idx = lua_absindex(L, idx); + lua_pushlightuserdata(L, const_cast(p)); + // put key behind value + lua_insert(L, -2); + lua_rawset(L, idx); +} + +#define LUA_OPEQ 1 +#define LUA_OPLT 2 +#define LUA_OPLE 3 + +inline int lua_compare(lua_State* L, int idx1, int idx2, int op) +{ + switch (op) + { + case LUA_OPEQ: + return lua_equal(L, idx1, idx2); + break; + + case LUA_OPLT: + return lua_lessthan(L, idx1, idx2); + break; + + case LUA_OPLE: + return lua_equal(L, idx1, idx2) || lua_lessthan(L, idx1, idx2); + break; + + default: + return 0; + }; +} + +inline int get_length(lua_State* L, int idx) +{ + return int(lua_objlen(L, idx)); +} + +#else +inline int get_length(lua_State* L, int idx) +{ + lua_len(L, idx); + int len = int(luaL_checknumber(L, -1)); + lua_pop(L, 1); + return len; +} + +#endif + +#ifndef LUA_OK +#define LUABRIDGE_LUA_OK 0 +#else +#define LUABRIDGE_LUA_OK LUA_OK +#endif + +/** Get a table value, bypassing metamethods. + */ +inline void rawgetfield(lua_State* L, int index, char const* key) +{ + assert(lua_istable(L, index)); + index = lua_absindex(L, index); + lua_pushstring(L, key); + lua_rawget(L, index); +} + +/** Set a table value, bypassing metamethods. + */ +inline void rawsetfield(lua_State* L, int index, char const* key) +{ + assert(lua_istable(L, index)); + index = lua_absindex(L, index); + lua_pushstring(L, key); + lua_insert(L, -2); + lua_rawset(L, index); +} + +/** Returns true if the value is a full userdata (not light). + */ +inline bool isfulluserdata(lua_State* L, int index) +{ + return lua_isuserdata(L, index) && !lua_islightuserdata(L, index); +} + +/** Test lua_State objects for global equality. + + This can determine if two different lua_State objects really point + to the same global state, such as when using coroutines. + + @note This is used for assertions. +*/ +inline bool equalstates(lua_State* L1, lua_State* L2) +{ + return lua_topointer(L1, LUA_REGISTRYINDEX) == lua_topointer(L2, LUA_REGISTRYINDEX); +} + +} // namespace luabridge diff --git a/csgo2/LuaBridge/luaBridge/detail/LuaRef.h b/csgo2/LuaBridge/luaBridge/detail/LuaRef.h new file mode 100644 index 0000000..ace12f1 --- /dev/null +++ b/csgo2/LuaBridge/luaBridge/detail/LuaRef.h @@ -0,0 +1,1012 @@ +// https://github.com/vinniefalco/LuaBridge +// Copyright 2018, Dmitry Tarakanov +// Copyright 2012, Vinnie Falco +// Copyright 2008, Nigel Atkinson +// SPDX-License-Identifier: MIT + +#pragma once + +#include +#include + +#include +#include +#include +#include + +namespace luabridge { + +//------------------------------------------------------------------------------ +/** + Type tag for representing LUA_TNIL. + + Construct one of these using `Nil ()` to represent a Lua nil. This is faster + than creating a reference in the registry to nil. Example: + + LuaRef t (LuaRef::createTable (L)); + ... + t ["k"] = Nil (); // assign nil +*/ +struct Nil +{ +}; + +//------------------------------------------------------------------------------ +/** + Stack specialization for Nil. +*/ +template<> +struct Stack +{ + static void push(lua_State* L, Nil) { lua_pushnil(L); } + + static bool isInstance(lua_State* L, int index) { return lua_type(L, index) == LUA_TNIL; } +}; + +/** + * Base class for Lua variables and table item reference classes. + */ +template +class LuaRefBase +{ +protected: + //---------------------------------------------------------------------------- + /** + Pop the Lua stack. + + Pops the specified number of stack items on destruction. We use this + when returning objects, to avoid an explicit temporary variable, since + the destructor executes after the return statement. For example: + + template + U cast (lua_State* L) + { + StackPop p (L, 1); + ... + return U (); // dtor called after this line + } + + @note The `StackPop` object must always be a named local variable. + */ + class StackPop + { + public: + /** Create a StackPop object. + + @param L A Lua state. + @param count The number of stack entries to pop on destruction. + */ + StackPop(lua_State* L, int count) : m_L(L), m_count(count) {} + + ~StackPop() { lua_pop(m_L, m_count); } + + private: + lua_State* m_L; + int m_count; + }; + + friend struct Stack; + + //---------------------------------------------------------------------------- + /** + Type tag for stack construction. + */ + struct FromStack + { + }; + + LuaRefBase(lua_State* L) : m_L(L) {} + + //---------------------------------------------------------------------------- + /** + Create a reference to this reference. + + @returns An index in the Lua registry. + */ + int createRef() const + { + impl().push(); + return luaL_ref(m_L, LUA_REGISTRYINDEX); + } + +public: + //---------------------------------------------------------------------------- + /** + Convert to a string using lua_tostring function. + + @returns A string representation of the referred Lua value. + */ + std::string tostring() const + { + lua_getglobal(m_L, "tostring"); + impl().push(); + lua_call(m_L, 1, 1); + const char* str = lua_tostring(m_L, -1); + lua_pop(m_L, 1); + return str; + } + + //---------------------------------------------------------------------------- + /** + Print a text description of the value to a stream. + This is used for diagnostics. + + @param os An output stream. + */ + void print(std::ostream& os) const + { + switch (type()) + { + case LUA_TNIL: + os << "nil"; + break; + + case LUA_TNUMBER: + os << cast(); + break; + + case LUA_TBOOLEAN: + os << (cast() ? "true" : "false"); + break; + + case LUA_TSTRING: + os << '"' << cast() << '"'; + break; + + case LUA_TTABLE: + os << "table: " << tostring(); + break; + + case LUA_TFUNCTION: + os << "function: " << tostring(); + break; + + case LUA_TUSERDATA: + os << "userdata: " << tostring(); + break; + + case LUA_TTHREAD: + os << "thread: " << tostring(); + break; + + case LUA_TLIGHTUSERDATA: + os << "lightuserdata: " << tostring(); + break; + + default: + os << "unknown"; + break; + } + } + + //------------------------------------------------------------------------------ + /** + Insert a Lua value or table item reference to a stream. + + @param os An output stream. + @param ref A Lua reference. + @returns The output stream. + */ + friend std::ostream& operator<<(std::ostream& os, LuaRefBase const& ref) + { + ref.print(os); + return os; + } + + //============================================================================ + // + // This group of member functions is mirrored in TableItem + // + + /** Retrieve the lua_State associated with the reference. + + @returns A Lua state. + */ + lua_State* state() const { return m_L; } + + //---------------------------------------------------------------------------- + /** + Place the object onto the Lua stack. + + @param L A Lua state. + */ + void push(lua_State* L) const + { + assert(equalstates(L, m_L)); + (void) L; + impl().push(); + } + + //---------------------------------------------------------------------------- + /** + Pop the top of Lua stack and assign it to the reference. + + @param L A Lua state. + */ + void pop(lua_State* L) + { + assert(equalstates(L, m_L)); + (void) L; + impl().pop(); + } + + //---------------------------------------------------------------------------- + /** + Return the Lua type of the referred value. This invokes lua_type(). + + @returns The type of the referred value. + @see lua_type() + */ + /** @{ */ + int type() const + { + impl().push(); + StackPop p(m_L, 1); + return lua_type(m_L, -1); + } + + // should never happen + // bool isNone () const { return m_ref == LUA_NOREF; } + + /// Indicate whether it is a nil reference. + /// + /// @returns True if this is a nil reference, false otherwise. + /// + bool isNil() const { return type() == LUA_TNIL; } + + /// Indicate whether it is a reference to a boolean. + /// + /// @returns True if it is a reference to a boolean, false otherwise. + /// + bool isBool() const { return type() == LUA_TBOOLEAN; } + + /// Indicate whether it is a reference to a number. + /// + /// @returns True if it is a reference to a number, false otherwise. + /// + bool isNumber() const { return type() == LUA_TNUMBER; } + + /// Indicate whether it is a reference to a string. + /// + /// @returns True if it is a reference to a string, false otherwise. + /// + bool isString() const { return type() == LUA_TSTRING; } + + /// Indicate whether it is a reference to a table. + /// + /// @returns True if it is a reference to a table, false otherwise. + /// + bool isTable() const { return type() == LUA_TTABLE; } + + /// Indicate whether it is a reference to a function. + /// + /// @returns True if it is a reference to a function, false otherwise. + /// + bool isFunction() const { return type() == LUA_TFUNCTION; } + + /// Indicate whether it is a reference to a full userdata. + /// + /// @returns True if it is a reference to a full userdata, false otherwise. + /// + bool isUserdata() const { return type() == LUA_TUSERDATA; } + + /// Indicate whether it is a reference to a Lua thread. + /// + /// @returns True if it is a reference to a Lua thread, false otherwise. + /// + bool isThread() const { return type() == LUA_TTHREAD; } + + /// Indicate whether it is a reference to a light userdata. + /// + /// @returns True if it is a reference to a light userdata, false otherwise. + /// + bool isLightUserdata() const { return type() == LUA_TLIGHTUSERDATA; } + + /** @} */ + + //---------------------------------------------------------------------------- + /** + Perform an explicit conversion to the type T. + + @returns A value of the type T converted from this reference. + */ + template + T cast() const + { + StackPop p(m_L, 1); + impl().push(); + return Stack::get(m_L, -1); + } + + //---------------------------------------------------------------------------- + /** + Indicate if this reference is convertible to the type T. + + @returns True if the referred value is convertible to the type T, + false otherwise. + */ + template + bool isInstance() const + { + StackPop p(m_L, 1); + impl().push(); + return Stack::isInstance(m_L, -1); + } + + //---------------------------------------------------------------------------- + /** + Type cast operator. + + @returns A value of the type T converted from this reference. + */ + template + operator T() const + { + return cast(); + } + + //---------------------------------------------------------------------------- + /** @{ */ + /** + Compare this reference with a specified value using lua_compare(). + This invokes metamethods. + + @param rhs A value to compare with. + @returns True if the referred value is equal to the specified one. + */ + template + bool operator==(T const& rhs) const + { + StackPop p(m_L, 2); + impl().push(); + Stack::push(m_L, rhs); + return lua_compare(m_L, -2, -1, LUA_OPEQ) == 1; + } + + /** + Compare this reference with a specified value using lua_compare(). + This invokes metamethods. + + @param rhs A value to compare with. + @returns True if the referred value is less than the specified one. + */ + template + bool operator<(T const& rhs) const + { + StackPop p(m_L, 2); + impl().push(); + ; + Stack::push(m_L, rhs); + int lhsType = lua_type(m_L, -2); + int rhsType = lua_type(m_L, -1); + if (lhsType != rhsType) + { + return lhsType < rhsType; + } + return lua_compare(m_L, -2, -1, LUA_OPLT) == 1; + } + + /** + Compare this reference with a specified value using lua_compare(). + This invokes metamethods. + + @param rhs A value to compare with. + @returns True if the referred value is less than or equal to the specified one. + */ + template + bool operator<=(T const& rhs) const + { + StackPop p(m_L, 2); + impl().push(); + ; + Stack::push(m_L, rhs); + int lhsType = lua_type(m_L, -2); + int rhsType = lua_type(m_L, -1); + if (lhsType != rhsType) + { + return lhsType <= rhsType; + } + return lua_compare(m_L, -2, -1, LUA_OPLE) == 1; + } + + /** + Compare this reference with a specified value using lua_compare(). + This invokes metamethods. + + @param rhs A value to compare with. + @returns True if the referred value is greater than the specified one. + */ + template + bool operator>(T const& rhs) const + { + StackPop p(m_L, 2); + impl().push(); + ; + Stack::push(m_L, rhs); + int lhsType = lua_type(m_L, -2); + int rhsType = lua_type(m_L, -1); + if (lhsType != rhsType) + { + return lhsType > rhsType; + } + return lua_compare(m_L, -1, -2, LUA_OPLT) == 1; + } + + /** + Compare this reference with a specified value using lua_compare(). + This invokes metamethods. + + @param rhs A value to compare with. + @returns True if the referred value is greater than or equal to the specified one. + */ + template + bool operator>=(T rhs) const + { + StackPop p(m_L, 2); + impl().push(); + ; + Stack::push(m_L, rhs); + int lhsType = lua_type(m_L, -2); + int rhsType = lua_type(m_L, -1); + if (lhsType != rhsType) + { + return lhsType >= rhsType; + } + return lua_compare(m_L, -1, -2, LUA_OPLE) == 1; + } + + /** + Compare this reference with a specified value using lua_compare(). + This does not invoke metamethods. + + @param rhs A value to compare with. + @returns True if the referred value is equal to the specified one. + */ + template + bool rawequal(T const& rhs) const + { + StackPop p(m_L, 2); + impl().push(); + ; + Stack::push(m_L, rhs); + return lua_rawequal(m_L, -1, -2) == 1; + } + /** @} */ + + //---------------------------------------------------------------------------- + /** + Append a value to a referred table. + If the table is a sequence this will add another element to it. + + @param v A value to append to the table. + */ + template + void append(T const& v) const + { + impl().push(); + ; + Stack::push(m_L, v); + luaL_ref(m_L, -2); + lua_pop(m_L, 1); + } + + //---------------------------------------------------------------------------- + /** + Return the length of a referred array. + This is identical to applying the Lua # operator. + + @returns The length of the referred array. + */ + int length() const + { + StackPop p(m_L, 1); + impl().push(); + ; + return get_length(m_L, -1); + } + + //---------------------------------------------------------------------------- + /** + Call Lua code with a variable amount of parameters. + The return value is provided as a LuaRef (which may be LUA_REFNIL). + If an error occurs, a LuaException is thrown. + + @returns A result of the call. + */ + template + LuaRef operator()(Arguments&&... arguments) const + { + impl().push(); + pushArguments(std::forward(arguments)...); + LuaException::pcall(m_L, sizeof...(arguments), 1); + return LuaRef::fromStack(m_L); + } + + //============================================================================ + +protected: + lua_State* m_L; + +private: + const Impl& impl() const { return static_cast(*this); } + + Impl& impl() { return static_cast(*this); } + + void pushArguments() const {} + + template + void pushArguments(T const& argument, Arguments&&... arguments) const + { + Stack::push(m_L, argument); + + pushArguments(std::forward(arguments)...); + } +}; + +//------------------------------------------------------------------------------ +/** + Lightweight reference to a Lua object. + + The reference is maintained for the lifetime of the C++ object. +*/ +class LuaRef : public LuaRefBase +{ + //---------------------------------------------------------------------------- + /** + A proxy for representing table values. + */ + class TableItem : public LuaRefBase + { + friend class LuaRef; + + public: + //-------------------------------------------------------------------------- + /** + Construct a TableItem from a table value. + The table is in the registry, and the key is at the top of the stack. + The key is popped off the stack. + + @param L A lua state. + @param tableRef The index of a table in the Lua registry. + */ + TableItem(lua_State* L, int tableRef) + : LuaRefBase(L), m_tableRef(LUA_NOREF), m_keyRef(luaL_ref(L, LUA_REGISTRYINDEX)) + { + lua_rawgeti(m_L, LUA_REGISTRYINDEX, tableRef); + m_tableRef = luaL_ref(L, LUA_REGISTRYINDEX); + } + + //-------------------------------------------------------------------------- + /** + Create a TableItem via copy constructor. + It is best to avoid code paths that invoke this, because it creates + an extra temporary Lua reference. Typically this is done by passing + the TableItem parameter as a `const` reference. + + @param other Another Lua table item reference. + */ + TableItem(TableItem const& other) + : LuaRefBase(other.m_L), m_tableRef(LUA_NOREF), m_keyRef(LUA_NOREF) + { + lua_rawgeti(m_L, LUA_REGISTRYINDEX, other.m_tableRef); + m_tableRef = luaL_ref(m_L, LUA_REGISTRYINDEX); + + lua_rawgeti(m_L, LUA_REGISTRYINDEX, other.m_keyRef); + m_keyRef = luaL_ref(m_L, LUA_REGISTRYINDEX); + } + + //-------------------------------------------------------------------------- + /** + Destroy the proxy. + This does not destroy the table value. + */ + ~TableItem() + { + luaL_unref(m_L, LUA_REGISTRYINDEX, m_keyRef); + luaL_unref(m_L, LUA_REGISTRYINDEX, m_tableRef); + } + + //-------------------------------------------------------------------------- + /** + Assign a new value to this table key. + This may invoke metamethods. + + @tparam T The type of a value to assign. + @param v A value to assign. + @returns This reference. + */ + template + TableItem& operator=(T const& v) + { + StackPop p(m_L, 1); + lua_rawgeti(m_L, LUA_REGISTRYINDEX, m_tableRef); + lua_rawgeti(m_L, LUA_REGISTRYINDEX, m_keyRef); + Stack::push(m_L, v); + lua_settable(m_L, -3); + return *this; + } + + //-------------------------------------------------------------------------- + /** + Assign a new value to this table key. + The assignment is raw, no metamethods are invoked. + + @tparam T The type of a value to assign. + @param v A value to assign. + @returns This reference. + */ + template + TableItem& rawset(T const& v) + { + StackPop p(m_L, 1); + lua_rawgeti(m_L, LUA_REGISTRYINDEX, m_tableRef); + lua_rawgeti(m_L, LUA_REGISTRYINDEX, m_keyRef); + Stack::push(m_L, v); + lua_rawset(m_L, -3); + return *this; + } + + //-------------------------------------------------------------------------- + /** + Push the value onto the Lua stack. + */ + using LuaRefBase::push; + + void push() const + { + lua_rawgeti(m_L, LUA_REGISTRYINDEX, m_tableRef); + lua_rawgeti(m_L, LUA_REGISTRYINDEX, m_keyRef); + lua_gettable(m_L, -2); + lua_remove(m_L, -2); // remove the table + } + + //-------------------------------------------------------------------------- + /** + Access a table value using a key. + This invokes metamethods. + + @tparam T The type of a key. + @param key A key value. + @returns A Lua table item reference. + */ + template + TableItem operator[](T const& key) const + { + return LuaRef(*this)[key]; + } + + //-------------------------------------------------------------------------- + /** + Access a table value using a key. + The operation is raw, metamethods are not invoked. The result is + passed by value and may not be modified. + + @tparam T The type of a key. + @param key A key value. + @returns A Lua value reference. + */ + template + LuaRef rawget(T const& key) const + { + return LuaRef(*this).rawget(key); + } + + private: + int m_tableRef; + int m_keyRef; + }; + + friend struct Stack; + friend struct Stack; + + //---------------------------------------------------------------------------- + /** + Create a reference to an object at the top of the Lua stack and pop it. + This constructor is private and not invoked directly. + Instead, use the `fromStack` function. + + @param L A Lua state. + @note The object is popped. + */ + LuaRef(lua_State* L, FromStack) : LuaRefBase(L), m_ref(luaL_ref(m_L, LUA_REGISTRYINDEX)) {} + + //---------------------------------------------------------------------------- + /** + Create a reference to an object on the Lua stack. + This constructor is private and not invoked directly. + Instead, use the `fromStack` function. + + @param L A Lua state. + @param index The index of the value on the Lua stack. + @note The object is not popped. + */ + LuaRef(lua_State* L, int index, FromStack) : LuaRefBase(L), m_ref(LUA_NOREF) + { + lua_pushvalue(m_L, index); + m_ref = luaL_ref(m_L, LUA_REGISTRYINDEX); + } + +public: + //---------------------------------------------------------------------------- + /** + Create a nil reference. + The Lua reference may be assigned later. + + @param L A Lua state. + */ + LuaRef(lua_State* L) : LuaRefBase(L), m_ref(LUA_NOREF) {} + + //---------------------------------------------------------------------------- + /** + Push a value onto a Lua stack and return a reference to it. + + @param L A Lua state. + @param v A value to push. + */ + template + LuaRef(lua_State* L, T v) : LuaRefBase(L), m_ref(LUA_NOREF) + { + Stack::push(m_L, v); + m_ref = luaL_ref(m_L, LUA_REGISTRYINDEX); + } + + //---------------------------------------------------------------------------- + /** + Create a reference to a table item. + + @param v A table item reference. + */ + LuaRef(TableItem const& v) : LuaRefBase(v.state()), m_ref(v.createRef()) {} + + //---------------------------------------------------------------------------- + /** + Create a new reference to an existing Lua value. + + @param other An existing reference. + */ + LuaRef(LuaRef const& other) : LuaRefBase(other.m_L), m_ref(other.createRef()) {} + + //---------------------------------------------------------------------------- + /** + Destroy a reference. + + The corresponding Lua registry reference will be released. + + @note If the state refers to a thread, it is the responsibility of the + caller to ensure that the thread still exists when the LuaRef + is destroyed. + */ + ~LuaRef() { luaL_unref(m_L, LUA_REGISTRYINDEX, m_ref); } + + //---------------------------------------------------------------------------- + /** + Return a reference to a top Lua stack item. + The stack item is not popped. + + @param L A Lua state. + @returns A reference to a value on the top of a Lua stack. + */ + static LuaRef fromStack(lua_State* L) { return LuaRef(L, FromStack()); } + + //---------------------------------------------------------------------------- + /** + Return a reference to a Lua stack item with a specified index. + The stack item is not removed. + + @param L A Lua state. + @param index An index in the Lua stack. + @returns A reference to a value in a Lua stack. + */ + static LuaRef fromStack(lua_State* L, int index) + { + lua_pushvalue(L, index); + return LuaRef(L, FromStack()); + } + + //---------------------------------------------------------------------------- + /** + Create a new empty table on the top of a Lua stack + and return a reference to it. + + @param L A Lua state. + @returns A reference to the newly created table. + @see luabridge::newTable() + */ + static LuaRef newTable(lua_State* L) + { + lua_newtable(L); + return LuaRef(L, FromStack()); + } + + //---------------------------------------------------------------------------- + /** + Return a reference to a named global Lua variable. + + @param L A Lua state. + @param name The name of a global variable. + @returns A reference to the Lua variable. + @see luabridge::getGlobal() + */ + static LuaRef getGlobal(lua_State* L, char const* name) + { + lua_getglobal(L, name); + return LuaRef(L, FromStack()); + } + + //---------------------------------------------------------------------------- + /** + Assign another LuaRef to this LuaRef. + + @param rhs A reference to assign from. + @returns This reference. + */ + LuaRef& operator=(LuaRef const& rhs) + { + LuaRef ref(rhs); + swap(ref); + return *this; + } + + //---------------------------------------------------------------------------- + /** + Assign a table item reference. + + @param rhs A table item reference. + @returns This reference. + */ + LuaRef& operator=(LuaRef::TableItem const& rhs) + { + LuaRef ref(rhs); + swap(ref); + return *this; + } + + //---------------------------------------------------------------------------- + /** + Assign nil to this reference. + + @returns This reference. + */ + LuaRef& operator=(Nil const&) + { + LuaRef ref(m_L); + swap(ref); + return *this; + } + + //---------------------------------------------------------------------------- + /** + Assign a different value to this reference. + + @param rhs A value to assign. + @returns This reference. + */ + template + LuaRef& operator=(T const& rhs) + { + LuaRef ref(m_L, rhs); + swap(ref); + return *this; + } + + //---------------------------------------------------------------------------- + /** + Place the object onto the Lua stack. + */ + using LuaRefBase::push; + + void push() const { lua_rawgeti(m_L, LUA_REGISTRYINDEX, m_ref); } + + //---------------------------------------------------------------------------- + /** + Pop the top of Lua stack and assign the ref to m_ref + */ + void pop() + { + luaL_unref(m_L, LUA_REGISTRYINDEX, m_ref); + m_ref = luaL_ref(m_L, LUA_REGISTRYINDEX); + } + + //---------------------------------------------------------------------------- + /** + Access a table value using a key. + This invokes metamethods. + + @param key A key in the table. + @returns A reference to the table item. + */ + template + TableItem operator[](T key) const + { + Stack::push(m_L, key); + return TableItem(m_L, m_ref); + } + + //-------------------------------------------------------------------------- + /** + Access a table value using a key. + The operation is raw, metamethods are not invoked. The result is + passed by value and may not be modified. + + @param key A key in the table. + @returns A reference to the table item. + */ + template + LuaRef rawget(T const& key) const + { + StackPop(m_L, 1); + push(m_L); + Stack::push(m_L, key); + lua_rawget(m_L, -2); + return LuaRef(m_L, FromStack()); + } + +private: + void swap(LuaRef& other) + { + std::swap(m_L, other.m_L); + std::swap(m_ref, other.m_ref); + } + + int m_ref; +}; + +//------------------------------------------------------------------------------ +/** + * Stack specialization for `LuaRef`. + */ +template<> +struct Stack +{ + // The value is const& to prevent a copy construction. + // + static void push(lua_State* L, LuaRef const& v) { v.push(L); } + + static LuaRef get(lua_State* L, int index) { return LuaRef::fromStack(L, index); } +}; + +//------------------------------------------------------------------------------ +/** + * Stack specialization for `TableItem`. + */ +template<> +struct Stack +{ + // The value is const& to prevent a copy construction. + // + static void push(lua_State* L, LuaRef::TableItem const& v) { v.push(L); } +}; + +//------------------------------------------------------------------------------ +/** + Create a reference to a new, empty table. + + This is a syntactic abbreviation for LuaRef::newTable (). +*/ +inline LuaRef newTable(lua_State* L) +{ + return LuaRef::newTable(L); +} + +//------------------------------------------------------------------------------ +/** + Create a reference to a value in the global table. + + This is a syntactic abbreviation for LuaRef::getGlobal (). +*/ +inline LuaRef getGlobal(lua_State* L, char const* name) +{ + return LuaRef::getGlobal(L, name); +} + +//------------------------------------------------------------------------------ + +// more C++-like cast syntax +// +template +T LuaRef_cast(LuaRef const& lr) +{ + return lr.cast(); +} + +} // namespace luabridge diff --git a/csgo2/LuaBridge/luaBridge/detail/Namespace.h b/csgo2/LuaBridge/luaBridge/detail/Namespace.h new file mode 100644 index 0000000..861fdd2 --- /dev/null +++ b/csgo2/LuaBridge/luaBridge/detail/Namespace.h @@ -0,0 +1,1395 @@ +// https://github.com/vinniefalco/LuaBridge +// Copyright 2019, Dmitry Tarakanov +// Copyright 2012, Vinnie Falco +// Copyright 2007, Nathan Reed +// SPDX-License-Identifier: MIT + +#pragma once + +#include +#include +#include +#include +#include + +#include +#include + +namespace luabridge { + +namespace detail { + +/** + * Base for class and namespace registration. + * Maintains Lua stack in the proper state. + * Once beginNamespace, beginClass or deriveClass is called the parent + * object upon its destruction may no longer clear the Lua stack. + * Then endNamespace or endClass is called, a new parent is created + * and the child transfers the responsibility for clearing stack to it. + * So there can be maximum one "active" registrar object. + */ +class Registrar +{ +protected: + lua_State* const L; + int mutable m_stackSize; + + Registrar(lua_State* L) : L(L), m_stackSize(0) {} + + Registrar(const Registrar& rhs) : L(rhs.L), m_stackSize(rhs.m_stackSize) + { + rhs.m_stackSize = 0; + } + +#ifndef _MSC_VER + // MS compiler thinks it's the 2nd copy ctor + Registrar(Registrar& rhs) : L(rhs.L), m_stackSize(rhs.m_stackSize) { rhs.m_stackSize = 0; } +#endif // ifndef _MSC_VER + + Registrar& operator=(const Registrar& rhs) + { + Registrar tmp(rhs); + std::swap(m_stackSize, tmp.m_stackSize); + return *this; + } + + ~Registrar() + { + if (m_stackSize > 0) + { + assert(m_stackSize <= lua_gettop(L)); + lua_pop(L, m_stackSize); + } + } + + void assertIsActive() const + { + if (m_stackSize == 0) + { + throw std::logic_error("Unable to continue registration"); + } + } +}; + +} // namespace detail + +/** Provides C++ to Lua registration capabilities. + + This class is not instantiated directly, call `getGlobalNamespace` to start + the registration process. +*/ +class Namespace : public detail::Registrar +{ + typedef detail::CFunc CFunc; + + //============================================================================ +#if 0 + /** + Error reporting. + + VF: This function looks handy, why aren't we using it? + */ + static int luaError (lua_State* L, std::string message) + { + assert (lua_isstring (L, lua_upvalueindex (1))); + std::string s; + + // Get information on the caller's caller to format the message, + // so the error appears to originate from the Lua source. + lua_Debug ar; + int result = lua_getstack (L, 2, &ar); + if (result != 0) + { + lua_getinfo (L, "Sl", &ar); + s = ar.short_src; + if (ar.currentline != -1) + { + // poor mans int to string to avoid . + lua_pushnumber (L, ar.currentline); + s = s + ":" + lua_tostring (L, -1) + ": "; + lua_pop (L, 1); + } + } + + s = s + message; + + return luaL_error (L, s.c_str ()); + } +#endif + + /** + Factored base to reduce template instantiations. + */ + class ClassBase : public detail::Registrar + { + public: + explicit ClassBase(Namespace& parent) : Registrar(parent) {} + + using Registrar::operator=; + + protected: + //-------------------------------------------------------------------------- + /** + Create the const table. + */ + void createConstTable(const char* name, bool trueConst = true) + { + std::string type_name = std::string(trueConst ? "const " : "") + name; + + // Stack: namespace table (ns) + lua_newtable(L); // Stack: ns, const table (co) + lua_pushvalue(L, -1); // Stack: ns, co, co + lua_setmetatable(L, -2); // co.__metatable = co. Stack: ns, co + + lua_pushstring(L, type_name.c_str()); + lua_rawsetp(L, -2, detail::getTypeKey()); // co [typeKey] = name. Stack: ns, co + + lua_pushcfunction(L, &CFunc::indexMetaMethod); + rawsetfield(L, -2, "__index"); + + lua_pushcfunction(L, &CFunc::newindexObjectMetaMethod); + rawsetfield(L, -2, "__newindex"); + + lua_newtable(L); + lua_rawsetp(L, -2, detail::getPropgetKey()); + + if (Security::hideMetatables()) + { + lua_pushnil(L); + rawsetfield(L, -2, "__metatable"); + } + } + + //-------------------------------------------------------------------------- + /** + Create the class table. + + The Lua stack should have the const table on top. + */ + void createClassTable(char const* name) + { + // Stack: namespace table (ns), const table (co) + + // Class table is the same as const table except the propset table + createConstTable(name, false); // Stack: ns, co, cl + + lua_newtable(L); // Stack: ns, co, cl, propset table (ps) + lua_rawsetp(L, -2, detail::getPropsetKey()); // cl [propsetKey] = ps. Stack: ns, co, cl + + lua_pushvalue(L, -2); // Stack: ns, co, cl, co + lua_rawsetp(L, -2, detail::getConstKey()); // cl [constKey] = co. Stack: ns, co, cl + + lua_pushvalue(L, -1); // Stack: ns, co, cl, cl + lua_rawsetp(L, -3, detail::getClassKey()); // co [classKey] = cl. Stack: ns, co, cl + } + + //-------------------------------------------------------------------------- + /** + Create the static table. + */ + void createStaticTable(char const* name) + { + // Stack: namespace table (ns), const table (co), class table (cl) + lua_newtable(L); // Stack: ns, co, cl, visible static table (vst) + lua_newtable(L); // Stack: ns, co, cl, st, static metatable (st) + lua_pushvalue(L, -1); // Stack: ns, co, cl, vst, st, st + lua_setmetatable(L, -3); // st.__metatable = mt. Stack: ns, co, cl, vst, st + lua_insert(L, -2); // Stack: ns, co, cl, st, vst + rawsetfield(L, -5, name); // ns [name] = vst. Stack: ns, co, cl, st + +#if 0 + lua_pushlightuserdata (L, this); + lua_pushcclosure (L, &tostringMetaMethod, 1); + rawsetfield (L, -2, "__tostring"); +#endif + lua_pushcfunction(L, &CFunc::indexMetaMethod); + rawsetfield(L, -2, "__index"); + + lua_pushcfunction(L, &CFunc::newindexStaticMetaMethod); + rawsetfield(L, -2, "__newindex"); + + lua_newtable(L); // Stack: ns, co, cl, st, proget table (pg) + lua_rawsetp( + L, -2, detail::getPropgetKey()); // st [propgetKey] = pg. Stack: ns, co, cl, st + + lua_newtable(L); // Stack: ns, co, cl, st, propset table (ps) + lua_rawsetp( + L, -2, detail::getPropsetKey()); // st [propsetKey] = pg. Stack: ns, co, cl, st + + lua_pushvalue(L, -2); // Stack: ns, co, cl, st, cl + lua_rawsetp(L, -2, detail::getClassKey()); // st [classKey] = cl. Stack: ns, co, cl, st + + if (Security::hideMetatables()) + { + lua_pushnil(L); + rawsetfield(L, -2, "__metatable"); + } + } + + //========================================================================== + /** + lua_CFunction to construct a class object wrapped in a container. + */ + template + static int ctorContainerProxy(lua_State* L) + { + typedef typename ContainerTraits::Type T; + detail::ArgList args(L); + T* const p = detail::Constructor::call(args); + detail::UserdataSharedHelper::push(L, p); + return 1; + } + + //-------------------------------------------------------------------------- + /** + lua_CFunction to construct a class object in-place in the userdata. + */ + template + static int ctorPlacementProxy(lua_State* L) + { + detail::ArgList args(L); + detail::UserdataValue* value = detail::UserdataValue::place(L); + detail::Constructor::call(value->getObject(), args); + value->commit(); + return 1; + } + + void assertStackState() const + { + // Stack: const table (co), class table (cl), static table (st) + assert(lua_istable(L, -3)); + assert(lua_istable(L, -2)); + assert(lua_istable(L, -1)); + } + }; + + //============================================================================ + // + // Class + // + //============================================================================ + /** + Provides a class registration in a lua_State. + + After construction the Lua stack holds these objects: + -1 static table + -2 class table + -3 const table + -4 enclosing namespace table + */ + template + class Class : public ClassBase + { + typedef detail::CFunc CFunc; + + public: + //========================================================================== + /** + Register a new class or add to an existing class registration. + + @param name The new class name. + @param parent A parent namespace object. + */ + Class(char const* name, Namespace& parent) : ClassBase(parent) + { + assert(lua_istable(L, -1)); // Stack: namespace table (ns) + rawgetfield(L, -1, name); // Stack: ns, static table (st) | nil + + if (lua_isnil(L, -1)) // Stack: ns, nil + { + lua_pop(L, 1); // Stack: ns + + createConstTable(name); // Stack: ns, const table (co) + lua_pushcfunction(L, &CFunc::gcMetaMethod); // Stack: ns, co, function + rawsetfield(L, -2, "__gc"); // co ["__gc"] = function. Stack: ns, co + ++m_stackSize; + + createClassTable(name); // Stack: ns, co, class table (cl) + lua_pushcfunction(L, &CFunc::gcMetaMethod); // Stack: ns, co, cl, function + rawsetfield(L, -2, "__gc"); // cl ["__gc"] = function. Stack: ns, co, cl + ++m_stackSize; + + createStaticTable(name); // Stack: ns, co, cl, st + ++m_stackSize; + + // Map T back to its tables. + lua_pushvalue(L, -1); // Stack: ns, co, cl, st, st + lua_rawsetp(L, + LUA_REGISTRYINDEX, + detail::getStaticRegistryKey()); // Stack: ns, co, cl, st + lua_pushvalue(L, -2); // Stack: ns, co, cl, st, cl + lua_rawsetp(L, + LUA_REGISTRYINDEX, + detail::getClassRegistryKey()); // Stack: ns, co, cl, st + lua_pushvalue(L, -3); // Stack: ns, co, cl, st, co + lua_rawsetp(L, + LUA_REGISTRYINDEX, + detail::getConstRegistryKey()); // Stack: ns, co, cl, st + } + else + { + assert(lua_istable(L, -1)); // Stack: ns, st + ++m_stackSize; + + // Map T back from its stored tables + + lua_rawgetp( + L, LUA_REGISTRYINDEX, detail::getConstRegistryKey()); // Stack: ns, st, co + lua_insert(L, -2); // Stack: ns, co, st + ++m_stackSize; + + lua_rawgetp(L, + LUA_REGISTRYINDEX, + detail::getClassRegistryKey()); // Stack: ns, co, st, cl + lua_insert(L, -2); // Stack: ns, co, cl, st + ++m_stackSize; + } + } + + //========================================================================== + /** + Derive a new class. + + @param name The class name. + @param parent A parent namespace object. + @param staticKey + */ + Class(char const* name, Namespace& parent, void const* const staticKey) : ClassBase(parent) + { + assert(lua_istable(L, -1)); // Stack: namespace table (ns) + + createConstTable(name); // Stack: ns, const table (co) + lua_pushcfunction(L, &CFunc::gcMetaMethod); // Stack: ns, co, function + rawsetfield(L, -2, "__gc"); // co ["__gc"] = function. Stack: ns, co + ++m_stackSize; + + createClassTable(name); // Stack: ns, co, class table (cl) + lua_pushcfunction(L, &CFunc::gcMetaMethod); // Stack: ns, co, cl, function + rawsetfield(L, -2, "__gc"); // cl ["__gc"] = function. Stack: ns, co, cl + ++m_stackSize; + + createStaticTable(name); // Stack: ns, co, cl, st + ++m_stackSize; + + lua_rawgetp( + L, LUA_REGISTRYINDEX, staticKey); // Stack: ns, co, cl, st, parent st (pst) | nil + if (lua_isnil(L, -1)) // Stack: ns, co, cl, st, nil + { + ++m_stackSize; + throw std::runtime_error("Base class is not registered"); + } + + assert(lua_istable(L, -1)); // Stack: ns, co, cl, st, pst + + lua_rawgetp( + L, -1, detail::getClassKey()); // Stack: ns, co, cl, st, pst, parent cl (pcl) + assert(lua_istable(L, -1)); + + lua_rawgetp( + L, -1, detail::getConstKey()); // Stack: ns, co, cl, st, pst, pcl, parent co (pco) + assert(lua_istable(L, -1)); + + lua_rawsetp( + L, + -6, + detail::getParentKey()); // co [parentKey] = pco. Stack: ns, co, cl, st, pst, pcl + lua_rawsetp( + L, -4, detail::getParentKey()); // cl [parentKey] = pcl. Stack: ns, co, cl, st, pst + lua_rawsetp( + L, -2, detail::getParentKey()); // st [parentKey] = pst. Stack: ns, co, cl, st + + lua_pushvalue(L, -1); // Stack: ns, co, cl, st, st + lua_rawsetp( + L, LUA_REGISTRYINDEX, detail::getStaticRegistryKey()); // Stack: ns, co, cl, st + lua_pushvalue(L, -2); // Stack: ns, co, cl, st, cl + lua_rawsetp( + L, LUA_REGISTRYINDEX, detail::getClassRegistryKey()); // Stack: ns, co, cl, st + lua_pushvalue(L, -3); // Stack: ns, co, cl, st, co + lua_rawsetp( + L, LUA_REGISTRYINDEX, detail::getConstRegistryKey()); // Stack: ns, co, cl, st + } + + //-------------------------------------------------------------------------- + /** + Continue registration in the enclosing namespace. + + @returns A parent registration object. + */ + Namespace endClass() + { + assert(m_stackSize > 3); + m_stackSize -= 3; + lua_pop(L, 3); + return Namespace(*this); + } + + //-------------------------------------------------------------------------- + /** + Add or replace a static property. + + @tparam U The type of the property. + @param name The property name. + @param value A property value pointer. + @param isWritable True for a read-write, false for read-only property. + @returns This class registration object. + */ + template + Class& addStaticProperty(char const* name, U* value, bool isWritable = true) + { + return addStaticData(name, value, isWritable); + } + + //-------------------------------------------------------------------------- + /** + Add or replace a static property. + + @tparam U The type of the property. + @param name The property name. + @param value A property value pointer. + @param isWritable True for a read-write, false for read-only property. + @returns This class registration object. + */ + template + Class& addStaticData(char const* name, U* value, bool isWritable = true) + { + assertStackState(); // Stack: const table (co), class table (cl), static table (st) + + lua_pushlightuserdata(L, value); // Stack: co, cl, st, pointer + lua_pushcclosure(L, &CFunc::getVariable, 1); // Stack: co, cl, st, getter + CFunc::addGetter(L, name, -2); // Stack: co, cl, st + + if (isWritable) + { + lua_pushlightuserdata(L, value); // Stack: co, cl, st, ps, pointer + lua_pushcclosure(L, &CFunc::setVariable, 1); // Stack: co, cl, st, ps, setter + } + else + { + lua_pushstring(L, name); // Stack: co, cl, st, name + lua_pushcclosure(L, &CFunc::readOnlyError, 1); // Stack: co, cl, st, error_fn + } + CFunc::addSetter(L, name, -2); // Stack: co, cl, st + + return *this; + } + + //-------------------------------------------------------------------------- + /// Add or replace a static property member. + /// + /// @tparam U The type of the property. + /// @param name The property name. + /// @param get A property getter function pointer. + /// @param set A property setter function pointer, optional, nullable. + /// Omit or pass nullptr for a read-only property. + /// @returns This class registration object. + /// + template + Class& addStaticProperty(char const* name, U (*get)(), void (*set)(U) = 0) + { + assertStackState(); // Stack: const table (co), class table (cl), static table (st) + + lua_pushlightuserdata(L, + reinterpret_cast(get)); // Stack: co, cl, st, function ptr + lua_pushcclosure(L, &CFunc::Call::f, 1); // Stack: co, cl, st, getter + CFunc::addGetter(L, name, -2); // Stack: co, cl, st + + if (set != 0) + { + lua_pushlightuserdata( + L, reinterpret_cast(set)); // Stack: co, cl, st, function ptr + lua_pushcclosure(L, &CFunc::Call::f, 1); // Stack: co, cl, st, setter + } + else + { + lua_pushstring(L, name); // Stack: co, cl, st, ps, name + lua_pushcclosure(L, &CFunc::readOnlyError, 1); // Stack: co, cl, st, error_fn + } + CFunc::addSetter(L, name, -2); // Stack: co, cl, st + + return *this; + } + + //-------------------------------------------------------------------------- + /** + Add or replace a static member function. + */ + template + Class& addStaticFunction(char const* name, FP const fp) + { + assertStackState(); // Stack: const table (co), class table (cl), static table (st) + + lua_pushlightuserdata(L, + reinterpret_cast(fp)); // Stack: co, cl, st, function ptr + lua_pushcclosure(L, &CFunc::Call::f, 1); // co, cl, st, function + rawsetfield(L, -2, name); // co, cl, st + + return *this; + } + + //-------------------------------------------------------------------------- + /** + Add or replace a static member function by std::function. + */ + template + Class& addStaticFunction(char const* name, std::function function) + { + assertStackState(); // Stack: const table (co), class table (cl), static table (st) + + using FnType = decltype(function); + new (lua_newuserdata(L, sizeof(function))) + FnType(std::move(function)); // Stack: co, cl, st, function userdata (ud) + lua_newtable(L); // Stack: co, cl, st, ud, ud metatable (mt) + lua_pushcfunction( + L, &CFunc::gcMetaMethodAny); // Stack: co, cl, st, ud, mt, gc function + rawsetfield(L, -2, "__gc"); // Stack: co, cl, st, ud, mt + lua_setmetatable(L, -2); // Stack: co, cl, st, ud + lua_pushcclosure( + L, &CFunc::CallProxyFunctor::f, 1); // Stack: co, cl, st, function + rawsetfield(L, -2, name); // Stack: co, cl, st + + return *this; + } + + //-------------------------------------------------------------------------- + /** + Add or replace a lua_CFunction. + + @param name The name of the function. + @param fp A C-function pointer. + @returns This class registration object. + */ + Class& addStaticFunction(char const* name, int (*const fp)(lua_State*)) + { + return addStaticCFunction(name, fp); + } + + //-------------------------------------------------------------------------- + /** + Add or replace a lua_CFunction. + */ + Class& addStaticCFunction(char const* name, int (*const fp)(lua_State*)) + { + assertStackState(); // Stack: const table (co), class table (cl), static table (st) + + lua_pushcfunction(L, fp); // co, cl, st, function + rawsetfield(L, -2, name); // co, cl, st + + return *this; + } + + //-------------------------------------------------------------------------- + template + Class& addProperty(char const* name, U T::*mp, bool isWritable = true) + { + return addData(name, mp, isWritable); + } + + //-------------------------------------------------------------------------- + /** + Add or replace a data member. + */ + template + Class& addData(char const* name, U T::*mp, bool isWritable = true) + { + assertStackState(); // Stack: const table (co), class table (cl), static table (st) + + typedef const U T::*mp_t; + new (lua_newuserdata(L, sizeof(mp_t))) mp_t(mp); // Stack: co, cl, st, field ptr + lua_pushcclosure(L, &CFunc::getProperty, 1); // Stack: co, cl, st, getter + lua_pushvalue(L, -1); // Stack: co, cl, st, getter, getter + CFunc::addGetter(L, name, -5); // Stack: co, cl, st, getter + CFunc::addGetter(L, name, -3); // Stack: co, cl, st + + if (isWritable) + { + new (lua_newuserdata(L, sizeof(mp_t))) mp_t(mp); // Stack: co, cl, st, field ptr + lua_pushcclosure(L, &CFunc::setProperty, 1); // Stack: co, cl, st, setter + CFunc::addSetter(L, name, -3); // Stack: co, cl, st + } + + return *this; + } + + //-------------------------------------------------------------------------- + /** + Add or replace a property member. + */ + template + Class& addProperty(char const* name, TG (T::*get)() const, void (T::*set)(TS) = 0) + { + assertStackState(); // Stack: const table (co), class table (cl), static table (st) + + typedef TG (T::*get_t)() const; + new (lua_newuserdata(L, sizeof(get_t))) get_t(get); // Stack: co, cl, st, function ptr + lua_pushcclosure(L, &CFunc::CallConstMember::f, 1); // Stack: co, cl, st, getter + lua_pushvalue(L, -1); // Stack: co, cl, st, getter, getter + CFunc::addGetter(L, name, -5); // Stack: co, cl, st, getter + CFunc::addGetter(L, name, -3); // Stack: co, cl, st + + if (set != 0) + { + typedef void (T::*set_t)(TS); + new (lua_newuserdata(L, sizeof(set_t))) + set_t(set); // Stack: co, cl, st, function ptr + lua_pushcclosure(L, &CFunc::CallMember::f, 1); // Stack: co, cl, st, setter + CFunc::addSetter(L, name, -3); // Stack: co, cl, st + } + + return *this; + } + + //-------------------------------------------------------------------------- + /** + Add or replace a property member. + */ + template + Class& addProperty(char const* name, + TG (T::*get)(lua_State*) const, + void (T::*set)(TS, lua_State*) = 0) + { + assertStackState(); // Stack: const table (co), class table (cl), static table (st) + + typedef TG (T::*get_t)(lua_State*) const; + new (lua_newuserdata(L, sizeof(get_t))) get_t(get); // Stack: co, cl, st, function ptr + lua_pushcclosure(L, &CFunc::CallConstMember::f, 1); // Stack: co, cl, st, getter + lua_pushvalue(L, -1); // Stack: co, cl, st, getter, getter + CFunc::addGetter(L, name, -5); // Stack: co, cl, st, getter + CFunc::addGetter(L, name, -3); // Stack: co, cl, st + + if (set != 0) + { + typedef void (T::*set_t)(TS, lua_State*); + new (lua_newuserdata(L, sizeof(set_t))) + set_t(set); // Stack: co, cl, st, function ptr + lua_pushcclosure(L, &CFunc::CallMember::f, 1); // Stack: co, cl, st, setter + CFunc::addSetter(L, name, -3); // Stack: co, cl, st + } + + return *this; + } + + //-------------------------------------------------------------------------- + /** + Add or replace a property member, by proxy. + + When a class is closed for modification and does not provide (or cannot + provide) the function signatures necessary to implement get or set for + a property, this will allow non-member functions act as proxies. + + Both the get and the set functions require a T const* and T* in the first + argument respectively. + */ + template + Class& addProperty(char const* name, TG (*get)(T const*), void (*set)(T*, TS) = 0) + { + assertStackState(); // Stack: const table (co), class table (cl), static table (st) + + lua_pushlightuserdata(L, + reinterpret_cast(get)); // Stack: co, cl, st, function ptr + lua_pushcclosure(L, &CFunc::Call::f, 1); // Stack: co, cl, st, getter + lua_pushvalue(L, -1); // Stack: co, cl, st,, getter, getter + CFunc::addGetter(L, name, -5); // Stack: co, cl, st, getter + CFunc::addGetter(L, name, -3); // Stack: co, cl, st + + if (set != 0) + { + lua_pushlightuserdata( + L, reinterpret_cast(set)); // Stack: co, cl, st, function ptr + lua_pushcclosure( + L, &CFunc::Call::f, 1); // Stack: co, cl, st, setter + CFunc::addSetter(L, name, -3); // Stack: co, cl, st + } + + return *this; + } + + //-------------------------------------------------------------------------- + /** + Add or replace a property member, by proxy C-function. + + When a class is closed for modification and does not provide (or cannot + provide) the function signatures necessary to implement get or set for + a property, this will allow non-member functions act as proxies. + + The object userdata ('this') value is at the index 1. + The new value for set function is at the index 2. + */ + Class& addProperty(char const* name, int (*get)(lua_State*), int (*set)(lua_State*) = 0) + { + assertStackState(); // Stack: const table (co), class table (cl), static table (st) + + lua_pushcfunction(L, get); + lua_pushvalue(L, -1); // Stack: co, cl, st,, getter, getter + CFunc::addGetter(L, name, -5); // Stack: co, cl, st,, getter + CFunc::addGetter(L, name, -3); // Stack: co, cl, st, + + if (set != 0) + { + lua_pushcfunction(L, set); + CFunc::addSetter(L, name, -3); // Stack: co, cl, st, + } + + return *this; + } + + template + Class& addProperty(char const* name, + std::function get, + std::function set = nullptr) + { + using GetType = decltype(get); + new (lua_newuserdata(L, sizeof(get))) + GetType(std::move(get)); // Stack: co, cl, st, function userdata (ud) + lua_newtable(L); // Stack: co, cl, st, ud, ud metatable (mt) + lua_pushcfunction( + L, &CFunc::gcMetaMethodAny); // Stack: co, cl, st, ud, mt, gc function + rawsetfield(L, -2, "__gc"); // Stack: co, cl, st, ud, mt + lua_setmetatable(L, -2); // Stack: co, cl, st, ud + lua_pushcclosure( + L, &CFunc::CallProxyFunctor::f, 1); // Stack: co, cl, st, getter + lua_pushvalue(L, -1); // Stack: co, cl, st, getter, getter + CFunc::addGetter(L, name, -4); // Stack: co, cl, st, getter + CFunc::addGetter(L, name, -4); // Stack: co, cl, st + + if (set != nullptr) + { + using SetType = decltype(set); + new (lua_newuserdata(L, sizeof(set))) + SetType(std::move(set)); // Stack: co, cl, st, function userdata (ud) + lua_newtable(L); // Stack: co, cl, st, ud, ud metatable (mt) + lua_pushcfunction( + L, &CFunc::gcMetaMethodAny); // Stack: co, cl, st, ud, mt, gc function + rawsetfield(L, -2, "__gc"); // Stack: co, cl, st, ud, mt + lua_setmetatable(L, -2); // Stack: co, cl, st, ud + lua_pushcclosure( + L, &CFunc::CallProxyFunctor::f, 1); // Stack: co, cl, st, setter + CFunc::addSetter(L, name, -3); // Stack: co, cl, st + } + + return *this; + } + + //-------------------------------------------------------------------------- + /** + Add or replace a member function by std::function. + */ + template + Class& addFunction(char const* name, std::function function) + { + assertStackState(); // Stack: const table (co), class table (cl), static table (st) + + using FnType = decltype(function); + new (lua_newuserdata(L, sizeof(function))) + FnType(std::move(function)); // Stack: co, cl, st, function userdata (ud) + lua_newtable(L); // Stack: co, cl, st, ud, ud metatable (mt) + lua_pushcfunction( + L, &CFunc::gcMetaMethodAny); // Stack: co, cl, st, ud, mt, gc function + rawsetfield(L, -2, "__gc"); // Stack: co, cl, st, ud, mt + lua_setmetatable(L, -2); // Stack: co, cl, st, ud + lua_pushcclosure( + L, &CFunc::CallProxyFunctor::f, 1); // Stack: co, cl, st, function + rawsetfield(L, -3, name); // Stack: co, cl, st + + return *this; + } + + //-------------------------------------------------------------------------- + /** + Add or replace a const member function by std::function. + */ + template + Class& addFunction(char const* name, + std::function function) + { + assertStackState(); // Stack: const table (co), class table (cl), static table (st) + + using FnType = decltype(function); + new (lua_newuserdata(L, sizeof(function))) + FnType(std::move(function)); // Stack: co, cl, st, function userdata (ud) + lua_newtable(L); // Stack: co, cl, st, ud, ud metatable (mt) + lua_pushcfunction( + L, &CFunc::gcMetaMethodAny); // Stack: co, cl, st, ud, mt, gc function + rawsetfield(L, -2, "__gc"); // Stack: co, cl, st, ud, mt + lua_setmetatable(L, -2); // Stack: co, cl, st, ud + lua_pushcclosure( + L, &CFunc::CallProxyFunctor::f, 1); // Stack: co, cl, st, function + lua_pushvalue(L, -1); // Stack: co, cl, st, function, function + rawsetfield(L, -4, name); // Stack: co, cl, st, function + rawsetfield(L, -4, name); // Stack: co, cl, st + + return *this; + } + + //-------------------------------------------------------------------------- + /** + Add or replace a member function. + */ + template + Class& addFunction(char const* name, ReturnType (T::*mf)(Params...)) + { + using MemFn = ReturnType (T::*)(Params...); + + assertStackState(); // Stack: const table (co), class table (cl), static table (st) + + static const std::string GC = "__gc"; + if (name == GC) + { + throw std::logic_error(GC + " metamethod registration is forbidden"); + } + CFunc::CallMemberFunctionHelper::add(L, name, mf); + return *this; + } + + template + Class& addFunction(char const* name, ReturnType (T::*mf)(Params...) const) + { + using MemFn = ReturnType (T::*)(Params...) const; + + assertStackState(); // Stack: const table (co), class table (cl), static table (st) + + static const std::string GC = "__gc"; + if (name == GC) + { + throw std::logic_error(GC + " metamethod registration is forbidden"); + } + CFunc::CallMemberFunctionHelper::add(L, name, mf); + return *this; + } + + //-------------------------------------------------------------------------- + /** + Add or replace a proxy function. + */ + template + Class& addFunction(char const* name, ReturnType (*proxyFn)(T* object, Params...)) + { + assertStackState(); // Stack: const table (co), class table (cl), static table (st) + + static const std::string GC = "__gc"; + if (name == GC) + { + throw std::logic_error(GC + " metamethod registration is forbidden"); + } + using FnType = decltype(proxyFn); + lua_pushlightuserdata( + L, reinterpret_cast(proxyFn)); // Stack: co, cl, st, function ptr + lua_pushcclosure( + L, &CFunc::CallProxyFunction::f, 1); // Stack: co, cl, st, function + rawsetfield(L, -3, name); // Stack: co, cl, st + return *this; + } + + template + Class& addFunction(char const* name, ReturnType (*proxyFn)(const T* object, Params...)) + { + assertStackState(); // Stack: const table (co), class table (cl), static table (st) + + static const std::string GC = "__gc"; + if (name == GC) + { + throw std::logic_error(GC + " metamethod registration is forbidden"); + } + using FnType = decltype(proxyFn); + lua_pushlightuserdata( + L, reinterpret_cast(proxyFn)); // Stack: co, cl, st, function ptr + lua_pushcclosure( + L, &CFunc::CallProxyFunction::f, 1); // Stack: co, cl, st, function + lua_pushvalue(L, -1); // Stack: co, cl, st, function, function + rawsetfield(L, -4, name); // Stack: co, cl, st, function + rawsetfield(L, -4, name); // Stack: co, cl, st + return *this; + } + + //-------------------------------------------------------------------------- + /** + Add or replace a member lua_CFunction. + */ + Class& addFunction(char const* name, int (T::*mfp)(lua_State*)) + { + return addCFunction(name, mfp); + } + + //-------------------------------------------------------------------------- + /** + Add or replace a member lua_CFunction. + */ + Class& addCFunction(char const* name, int (T::*mfp)(lua_State*)) + { + assertStackState(); // Stack: const table (co), class table (cl), static table (st) + + typedef int (T::*MFP)(lua_State*); + new (lua_newuserdata(L, sizeof(mfp))) MFP(mfp); // Stack: co, cl, st, function ptr + lua_pushcclosure( + L, &CFunc::CallMemberCFunction::f, 1); // Stack: co, cl, st, function + rawsetfield(L, -3, name); // Stack: co, cl, st + + return *this; + } + + //-------------------------------------------------------------------------- + /** + Add or replace a const member lua_CFunction. + */ + Class& addFunction(char const* name, int (T::*mfp)(lua_State*) const) + { + return addCFunction(name, mfp); + } + + //-------------------------------------------------------------------------- + /** + Add or replace a const member lua_CFunction. + */ + Class& addCFunction(char const* name, int (T::*mfp)(lua_State*) const) + { + assertStackState(); // Stack: const table (co), class table (cl), static table (st) + + typedef int (T::*MFP)(lua_State*) const; + new (lua_newuserdata(L, sizeof(mfp))) MFP(mfp); + lua_pushcclosure(L, &CFunc::CallConstMemberCFunction::f, 1); + lua_pushvalue(L, -1); // Stack: co, cl, st, function, function + rawsetfield(L, -4, name); // Stack: co, cl, st, function + rawsetfield(L, -4, name); // Stack: co, cl, st + + return *this; + } + + //-------------------------------------------------------------------------- + /** + Add or replace a primary Constructor. + + The primary Constructor is invoked when calling the class type table + like a function. + + The template parameter should be a function pointer type that matches + the desired Constructor (since you can't take the address of a Constructor + and pass it as an argument). + */ + template + Class& addConstructor() + { + assertStackState(); // Stack: const table (co), class table (cl), static table (st) + + lua_pushcclosure( + L, &ctorContainerProxy::Params, C>, 0); + rawsetfield(L, -2, "__call"); + + return *this; + } + + template + Class& addConstructor() + { + assertStackState(); // Stack: const table (co), class table (cl), static table (st) + + lua_pushcclosure( + L, &ctorPlacementProxy::Params, T>, 0); + rawsetfield(L, -2, "__call"); + + return *this; + } + }; + +private: + //---------------------------------------------------------------------------- + /** + Open the global namespace for registrations. + + @param L A Lua state. + */ + explicit Namespace(lua_State* L) : Registrar(L) + { + lua_getglobal(L, "_G"); + ++m_stackSize; + } + + //---------------------------------------------------------------------------- + /** + Open a namespace for registrations. + The namespace is created if it doesn't already exist. + + @param name The namespace name. + @param parent The parent namespace object. + @pre The parent namespace is at the top of the Lua stack. + */ + Namespace(char const* name, Namespace& parent) : Registrar(parent) + { + assert(lua_istable(L, -1)); // Stack: parent namespace (pns) + + rawgetfield(L, -1, name); // Stack: pns, namespace (ns) | nil + + if (lua_isnil(L, -1)) // Stack: pns, nil + { + lua_pop(L, 1); // Stack: pns + + lua_newtable(L); // Stack: pns, ns + lua_pushvalue(L, -1); // Stack: pns, ns, ns + + // na.__metatable = ns + lua_setmetatable(L, -2); // Stack: pns, ns + + // ns.__index = indexMetaMethod + lua_pushcfunction(L, &CFunc::indexMetaMethod); + rawsetfield(L, -2, "__index"); // Stack: pns, ns + + // ns.__newindex = newindexMetaMethod + lua_pushcfunction(L, &CFunc::newindexStaticMetaMethod); + rawsetfield(L, -2, "__newindex"); // Stack: pns, ns + + lua_newtable(L); // Stack: pns, ns, propget table (pg) + lua_rawsetp(L, -2, detail::getPropgetKey()); // ns [propgetKey] = pg. Stack: pns, ns + + lua_newtable(L); // Stack: pns, ns, propset table (ps) + lua_rawsetp(L, -2, detail::getPropsetKey()); // ns [propsetKey] = ps. Stack: pns, ns + + // pns [name] = ns + lua_pushvalue(L, -1); // Stack: pns, ns, ns + rawsetfield(L, -3, name); // Stack: pns, ns +#if 0 + lua_pushcfunction (L, &tostringMetaMethod); + rawsetfield (L, -2, "__tostring"); +#endif + } + + ++m_stackSize; + } + + //---------------------------------------------------------------------------- + /** + Close the class and continue the namespace registrations. + + @param child A child class registration object. + */ + explicit Namespace(ClassBase& child) : Registrar(child) {} + + using Registrar::operator=; + +public: + //---------------------------------------------------------------------------- + /** + Retrieve the global namespace. + It is recommended to put your namespace inside the global namespace, and + then add your classes and functions to it, rather than adding many classes + and functions directly to the global namespace. + + @param L A Lua state. + @returns A namespace registration object. + */ + static Namespace getGlobalNamespace(lua_State* L) + { + enableExceptions(L); + return Namespace(L); + } + + //---------------------------------------------------------------------------- + /** + Open a new or existing namespace for registrations. + + @param name The namespace name. + @returns A namespace registration object. + */ + Namespace beginNamespace(char const* name) + { + assertIsActive(); + return Namespace(name, *this); + } + + //---------------------------------------------------------------------------- + /** + Continue namespace registration in the parent. + Do not use this on the global namespace. + + @returns A parent namespace registration object. + */ + Namespace endNamespace() + { + if (m_stackSize == 1) + { + throw std::logic_error("endNamespace () called on global namespace"); + } + + assert(m_stackSize > 1); + --m_stackSize; + lua_pop(L, 1); + return Namespace(*this); + } + + //---------------------------------------------------------------------------- + /** + Add or replace a property. + + @param name The property name. + @param value A value pointer. + @param isWritable True for a read-write, false for read-only property. + @returns This namespace registration object. + */ + template + Namespace& addProperty(char const* name, T* value, bool isWritable = true) + { + return addVariable(name, value, isWritable); + } + + //---------------------------------------------------------------------------- + /** + Add or replace a property. + + @param name The property name. + @param value A value pointer. + @param isWritable True for a read-write, false for read-only property. + @returns This namespace registration object. + */ + template + Namespace& addVariable(char const* name, T* value, bool isWritable = true) + { + if (m_stackSize == 1) + { + throw std::logic_error("addProperty () called on global namespace"); + } + + assert(lua_istable(L, -1)); // Stack: namespace table (ns) + + lua_pushlightuserdata(L, value); // Stack: ns, pointer + lua_pushcclosure(L, &CFunc::getVariable, 1); // Stack: ns, getter + CFunc::addGetter(L, name, -2); // Stack: ns + + if (isWritable) + { + lua_pushlightuserdata(L, value); // Stack: ns, pointer + lua_pushcclosure(L, &CFunc::setVariable, 1); // Stack: ns, setter + } + else + { + lua_pushstring(L, name); // Stack: ns, ps, name + lua_pushcclosure(L, &CFunc::readOnlyError, 1); // Stack: ns, error_fn + } + CFunc::addSetter(L, name, -2); // Stack: ns + + return *this; + } + template + Namespace& addConstant(char const* name, T value) + { + if (m_stackSize == 1) + { + throw std::logic_error("addConstant () called on global namespace"); + } + + assert(lua_istable(L, -1)); // Stack: namespace table (ns) + + Stack::push(L, value); // Stack: ns, value + rawsetfield(L, -2, name); // Stack: ns + + return *this; + } + + //---------------------------------------------------------------------------- + /** + Add or replace a property. + If the set function is omitted or null, the property is read-only. + + @param name The property name. + @param get A pointer to a property getter function. + @param set A pointer to a property setter function, optional. + @returns This namespace registration object. + */ + template + Namespace& addProperty(char const* name, TG (*get)(), void (*set)(TS) = 0) + { + if (m_stackSize == 1) + { + throw std::logic_error("addProperty () called on global namespace"); + } + + assert(lua_istable(L, -1)); // Stack: namespace table (ns) + + lua_pushlightuserdata(L, reinterpret_cast(get)); // Stack: ns, function ptr + lua_pushcclosure(L, &CFunc::Call::f, 1); // Stack: ns, getter + CFunc::addGetter(L, name, -2); + + if (set != 0) + { + lua_pushlightuserdata(L, reinterpret_cast(set)); // Stack: ns, function ptr + lua_pushcclosure(L, &CFunc::Call::f, 1); + } + else + { + lua_pushstring(L, name); + lua_pushcclosure(L, &CFunc::readOnlyError, 1); + } + CFunc::addSetter(L, name, -2); + + return *this; + } + + //---------------------------------------------------------------------------- + /** + Add or replace a property. + If the set function is omitted or null, the property is read-only. + + @param name The property name. + @param get A pointer to a property getter function. + @param set A pointer to a property setter function, optional. + @returns This namespace registration object. + */ + Namespace& addProperty(char const* name, int (*get)(lua_State*), int (*set)(lua_State*) = 0) + { + if (m_stackSize == 1) + { + throw std::logic_error("addProperty () called on global namespace"); + } + + assert(lua_istable(L, -1)); // Stack: namespace table (ns) + lua_pushcfunction(L, get); // Stack: ns, getter + CFunc::addGetter(L, name, -2); // Stack: ns + if (set != 0) + { + lua_pushcfunction(L, set); // Stack: ns, setter + CFunc::addSetter(L, name, -2); // Stack: ns + } + else + { + lua_pushstring(L, name); // Stack: ns, name + lua_pushcclosure(L, &CFunc::readOnlyError, 1); // Stack: ns, name, readOnlyError + CFunc::addSetter(L, name, -2); // Stack: ns + } + + return *this; + } + + //---------------------------------------------------------------------------- + /** + Add or replace a namespace function by std::function. + */ + template + Namespace& addFunction(char const* name, std::function function) + { + assert(lua_istable(L, -1)); // Stack: namespace table (ns) + + using FnType = decltype(function); + new (lua_newuserdata(L, sizeof(function))) + FnType(std::move(function)); // Stack: ns, function userdata (ud) + lua_newtable(L); // Stack: ns, ud, ud metatable (mt) + lua_pushcfunction(L, &CFunc::gcMetaMethodAny); // Stack: ns, ud, mt, gc function + rawsetfield(L, -2, "__gc"); // Stack: ns, ud, mt + lua_setmetatable(L, -2); // Stack: ns, ud + lua_pushcclosure(L, &CFunc::CallProxyFunctor::f, 1); // Stack: ns, function + rawsetfield(L, -2, name); // Stack: ns + + return *this; + } + + //---------------------------------------------------------------------------- + /** + Add or replace a free function. + */ + template + Namespace& addFunction(char const* name, ReturnType (*fp)(Params...)) + { + assert(lua_istable(L, -1)); // Stack: namespace table (ns) + + using FnType = decltype(fp); + lua_pushlightuserdata(L, reinterpret_cast(fp)); // Stack: ns, function ptr + lua_pushcclosure(L, &CFunc::Call::f, 1); // Stack: ns, function + rawsetfield(L, -2, name); // Stack: ns + + return *this; + } + +#ifdef _M_IX86 // Windows 32bit only + + //---------------------------------------------------------------------------- + /** + Add or replace a free __stdcall function. + */ + template + Namespace& addFunction(char const* name, ReturnType(__stdcall* fp)(Params...)) + { + assert(lua_istable(L, -1)); // Stack: namespace table (ns) + + using FnType = decltype(fp); + lua_pushlightuserdata(L, reinterpret_cast(fp)); // Stack: ns, function ptr + lua_pushcclosure(L, &CFunc::Call::f, 1); // Stack: ns, function + rawsetfield(L, -2, name); // Stack: ns + + return *this; + } + +#endif // _M_IX86 + + //---------------------------------------------------------------------------- + /** + Add or replace a lua_CFunction. + + @param name The function name. + @param fp A C-function pointer. + @returns This namespace registration object. + */ + Namespace& addFunction(char const* name, int (*const fp)(lua_State*)) + { + return addCFunction(name, fp); + } + + //---------------------------------------------------------------------------- + /** + Add or replace a lua_CFunction. + + @param name The function name. + @param fp A C-function pointer. + @returns This namespace registration object. + */ + Namespace& addCFunction(char const* name, int (*const fp)(lua_State*)) + { + assert(lua_istable(L, -1)); // Stack: namespace table (ns) + + lua_pushcfunction(L, fp); // Stack: ns, function + rawsetfield(L, -2, name); // Stack: ns + + return *this; + } + + //---------------------------------------------------------------------------- + /** + Open a new or existing class for registrations. + + @param name The class name. + @returns A class registration object. + */ + template + Class beginClass(char const* name) + { + assertIsActive(); + return Class(name, *this); + } + + //---------------------------------------------------------------------------- + /** + Derive a new class for registrations. + Call deriveClass() only once. + To continue registrations for the class later, use beginClass(). + + @param name The class name. + @returns A class registration object. + */ + template + Class deriveClass(char const* name) + { + assertIsActive(); + return Class(name, *this, detail::getStaticRegistryKey()); + } +}; + +//------------------------------------------------------------------------------ +/** + Retrieve the global namespace. + It is recommended to put your namespace inside the global namespace, and + then add your classes and functions to it, rather than adding many classes + and functions directly to the global namespace. + + @param L A Lua state. + @returns A namespace registration object. +*/ +inline Namespace getGlobalNamespace(lua_State* L) +{ + return Namespace::getGlobalNamespace(L); +} + +} // namespace luabridge diff --git a/csgo2/LuaBridge/luaBridge/detail/Security.h b/csgo2/LuaBridge/luaBridge/detail/Security.h new file mode 100644 index 0000000..6d924d7 --- /dev/null +++ b/csgo2/LuaBridge/luaBridge/detail/Security.h @@ -0,0 +1,58 @@ +// https://github.com/vinniefalco/LuaBridge +// Copyright 2012, Vinnie Falco +// SPDX-License-Identifier: MIT + +#pragma once + +namespace luabridge { + +//------------------------------------------------------------------------------ +/** +security options. +*/ +class Security +{ +public: + static bool hideMetatables() { return getSettings().hideMetatables; } + + static void setHideMetatables(bool shouldHide) { getSettings().hideMetatables = shouldHide; } + +private: + struct Settings + { + Settings() : hideMetatables(true) {} + + bool hideMetatables; + }; + + static Settings& getSettings() + { + static Settings settings; + return settings; + } +}; + +//------------------------------------------------------------------------------ +/** +Set a global value in the lua_State. + +@note This works on any type specialized by `Stack`, including `LuaRef` and +its table proxies. +*/ +template +inline void setGlobal(lua_State* L, T t, char const* name) +{ + push(L, t); + lua_setglobal(L, name); +} + +//------------------------------------------------------------------------------ +/** +Change whether or not metatables are hidden (on by default). +*/ +inline void setHideMetatables(bool shouldHide) +{ + Security::setHideMetatables(shouldHide); +} + +} // namespace luabridge diff --git a/csgo2/LuaBridge/luaBridge/detail/Stack.h b/csgo2/LuaBridge/luaBridge/detail/Stack.h new file mode 100644 index 0000000..62db469 --- /dev/null +++ b/csgo2/LuaBridge/luaBridge/detail/Stack.h @@ -0,0 +1,535 @@ +// https://github.com/vinniefalco/LuaBridge +// Copyright 2019, Dmitry Tarakanov +// Copyright 2012, Vinnie Falco +// Copyright 2007, Nathan Reed +// SPDX-License-Identifier: MIT + +#pragma once + +#include +#include + +#include +#ifdef LUABRIDGE_CXX17 +#include +#endif + +namespace luabridge { + +/// Lua stack traits for C++ types. +/// +/// @tparam T A C++ type. +/// +template +struct Stack; + +template<> +struct Stack +{ + static void push(lua_State*) {} +}; + +//------------------------------------------------------------------------------ +/** + Receive the lua_State* as an argument. +*/ +template<> +struct Stack +{ + static lua_State* get(lua_State* L, int) { return L; } +}; + +//------------------------------------------------------------------------------ +/** + Stack specialization for a lua_CFunction. +*/ +template<> +struct Stack +{ + static void push(lua_State* L, lua_CFunction f) { lua_pushcfunction(L, f); } + + static lua_CFunction get(lua_State* L, int index) { return lua_tocfunction(L, index); } + + static bool isInstance(lua_State* L, int index) { return lua_iscfunction(L, index); } +}; + +//------------------------------------------------------------------------------ +/** + Stack specialization for `int`. +*/ +template<> +struct Stack +{ + static void push(lua_State* L, int value) + { + lua_pushinteger(L, static_cast(value)); + } + + static int get(lua_State* L, int index) + { + return static_cast(luaL_checkinteger(L, index)); + } + + static bool isInstance(lua_State* L, int index) + { + if (lua_type(L, index) != LUA_TNUMBER) + { + return false; + } + +#if LUA_VERSION_NUM <= 501 + return true; +#else + int isNumber; + lua_tointegerx(L, index, &isNumber); + return isNumber; +#endif + } +}; + +//------------------------------------------------------------------------------ +/** + Stack specialization for `unsigned int`. +*/ +template<> +struct Stack +{ + static void push(lua_State* L, unsigned int value) + { + lua_pushinteger(L, static_cast(value)); + } + + static unsigned int get(lua_State* L, int index) + { + return static_cast(luaL_checkinteger(L, index)); + } + + static bool isInstance(lua_State* L, int index) { return Stack::isInstance(L, index); } +}; + +//------------------------------------------------------------------------------ +/** + Stack specialization for `unsigned char`. +*/ +template<> +struct Stack +{ + static void push(lua_State* L, unsigned char value) + { + lua_pushinteger(L, static_cast(value)); + } + + static unsigned char get(lua_State* L, int index) + { + return static_cast(luaL_checkinteger(L, index)); + } + + static bool isInstance(lua_State* L, int index) { return Stack::isInstance(L, index); } +}; + +//------------------------------------------------------------------------------ +/** + Stack specialization for `short`. +*/ +template<> +struct Stack +{ + static void push(lua_State* L, short value) + { + lua_pushinteger(L, static_cast(value)); + } + + static short get(lua_State* L, int index) + { + return static_cast(luaL_checkinteger(L, index)); + } + + static bool isInstance(lua_State* L, int index) { return Stack::isInstance(L, index); } +}; + +//------------------------------------------------------------------------------ +/** + Stack specialization for `unsigned short`. +*/ +template<> +struct Stack +{ + static void push(lua_State* L, unsigned short value) + { + lua_pushinteger(L, static_cast(value)); + } + + static unsigned short get(lua_State* L, int index) + { + return static_cast(luaL_checkinteger(L, index)); + } + + static bool isInstance(lua_State* L, int index) { return Stack::isInstance(L, index); } +}; + +//------------------------------------------------------------------------------ +/** + Stack specialization for `long`. +*/ +template<> +struct Stack +{ + static void push(lua_State* L, long value) + { + lua_pushinteger(L, static_cast(value)); + } + + static long get(lua_State* L, int index) + { + return static_cast(luaL_checkinteger(L, index)); + } + + static bool isInstance(lua_State* L, int index) { return Stack::isInstance(L, index); } +}; + +//------------------------------------------------------------------------------ +/** + Stack specialization for `unsigned long`. +*/ +template<> +struct Stack +{ + static void push(lua_State* L, unsigned long value) + { + lua_pushinteger(L, static_cast(value)); + } + + static unsigned long get(lua_State* L, int index) + { + return static_cast(luaL_checkinteger(L, index)); + } + + static bool isInstance(lua_State* L, int index) { return Stack::isInstance(L, index); } +}; + +//------------------------------------------------------------------------------ +/** + * Stack specialization for `long long`. + */ +template<> +struct Stack +{ + static void push(lua_State* L, long long value) + { + lua_pushinteger(L, static_cast(value)); + } + + static long long get(lua_State* L, int index) + { + return static_cast(luaL_checkinteger(L, index)); + } + + static bool isInstance(lua_State* L, int index) { return Stack::isInstance(L, index); } +}; + +//------------------------------------------------------------------------------ +/** + * Stack specialization for `unsigned long long`. + */ +template<> +struct Stack +{ + static void push(lua_State* L, unsigned long long value) + { + lua_pushinteger(L, static_cast(value)); + } + static unsigned long long get(lua_State* L, int index) + { + return static_cast(luaL_checkinteger(L, index)); + } + + static bool isInstance(lua_State* L, int index) { return Stack::isInstance(L, index); } +}; + +//------------------------------------------------------------------------------ +/** + Stack specialization for `float`. +*/ +template<> +struct Stack +{ + static void push(lua_State* L, float value) + { + lua_pushnumber(L, static_cast(value)); + } + + static float get(lua_State* L, int index) + { + return static_cast(luaL_checknumber(L, index)); + } + + static bool isInstance(lua_State* L, int index) { return lua_type(L, index) == LUA_TNUMBER; } +}; + +//------------------------------------------------------------------------------ +/** + Stack specialization for `double`. +*/ +template<> +struct Stack +{ + static void push(lua_State* L, double value) + { + lua_pushnumber(L, static_cast(value)); + } + + static double get(lua_State* L, int index) + { + return static_cast(luaL_checknumber(L, index)); + } + + static bool isInstance(lua_State* L, int index) { return lua_type(L, index) == LUA_TNUMBER; } +}; + +//------------------------------------------------------------------------------ +/** + Stack specialization for `bool`. +*/ +template<> +struct Stack +{ + static void push(lua_State* L, bool value) { lua_pushboolean(L, value ? 1 : 0); } + + static bool get(lua_State* L, int index) { return lua_toboolean(L, index) ? true : false; } + + static bool isInstance(lua_State* L, int index) { return lua_isboolean(L, index); } +}; + +//------------------------------------------------------------------------------ +/** + Stack specialization for `char`. +*/ +template<> +struct Stack +{ + static void push(lua_State* L, char value) { lua_pushlstring(L, &value, 1); } + + static char get(lua_State* L, int index) { return luaL_checkstring(L, index)[0]; } + + static bool isInstance(lua_State* L, int index) { return lua_type(L, index) == LUA_TSTRING; } +}; + +//------------------------------------------------------------------------------ +/** + Stack specialization for `const char*`. +*/ +template<> +struct Stack +{ + static void push(lua_State* L, char const* str) + { + if (str != 0) + lua_pushstring(L, str); + else + lua_pushnil(L); + } + + static char const* get(lua_State* L, int index) + { + return lua_isnil(L, index) ? 0 : luaL_checkstring(L, index); + } + + static bool isInstance(lua_State* L, int index) + { + return lua_isnil(L, index) || lua_type(L, index) == LUA_TSTRING; + } +}; + +//------------------------------------------------------------------------------ +/** + Stack specialization for `std::string`. +*/ +template<> +struct Stack +{ + static void push(lua_State* L, std::string const& str) + { + lua_pushlstring(L, str.data(), str.size()); + } + + static std::string get(lua_State* L, int index) + { + size_t len; + if (lua_type(L, index) == LUA_TSTRING) + { + const char* str = lua_tolstring(L, index, &len); + return std::string(str, len); + } + + // Lua reference manual: + // If the value is a number, then lua_tolstring also changes the actual value in the stack + // to a string. (This change confuses lua_next when lua_tolstring is applied to keys during + // a table traversal.) + lua_pushvalue(L, index); + const char* str = lua_tolstring(L, -1, &len); + std::string string(str, len); + lua_pop(L, 1); // Pop the temporary string + return string; + } + + static bool isInstance(lua_State* L, int index) { return lua_type(L, index) == LUA_TSTRING; } +}; + +#ifdef LUABRIDGE_CXX17 + +//------------------------------------------------------------------------------ +/** + Stack specialization for `std::string`. +*/ +template<> +struct Stack +{ + static void push(lua_State* L, std::string_view str) + { + lua_pushlstring(L, str.data(), str.size()); + } + + static std::string_view get(lua_State* L, int index) + { + size_t len; + if (lua_type(L, index) == LUA_TSTRING) + { + const char* str = lua_tolstring(L, index, &len); + return std::string_view(str, len); + } + + return {}; + } + + static bool isInstance(lua_State* L, int index) { return lua_type(L, index) == LUA_TSTRING; } +}; + +#endif // LUABRIDGE_CXX17 + +namespace detail { + +template +struct StackOpSelector +{ + typedef T ReturnType; + + static void push(lua_State* L, T& value) { Stack::push(L, value); } + + static ReturnType get(lua_State* L, int index) { return Stack::get(L, index); } + + static bool isInstance(lua_State* L, int index) { return Stack::isInstance(L, index); } +}; + +template +struct StackOpSelector +{ + typedef T ReturnType; + + static void push(lua_State* L, const T& value) { Stack::push(L, value); } + + static ReturnType get(lua_State* L, int index) { return Stack::get(L, index); } + + static bool isInstance(lua_State* L, int index) { return Stack::isInstance(L, index); } +}; + +template +struct StackOpSelector +{ + typedef T ReturnType; + + static void push(lua_State* L, T* value) { Stack::push(L, *value); } + + static ReturnType get(lua_State* L, int index) { return Stack::get(L, index); } + + static bool isInstance(lua_State* L, int index) { return Stack::isInstance(L, index); } +}; + +template +struct StackOpSelector +{ + typedef T ReturnType; + + static void push(lua_State* L, const T* value) { Stack::push(L, *value); } + + static ReturnType get(lua_State* L, int index) { return Stack::get(L, index); } + + static bool isInstance(lua_State* L, int index) { return Stack::isInstance(L, index); } +}; + +} // namespace detail + +template +struct Stack +{ + typedef detail::StackOpSelector::value> Helper; + typedef typename Helper::ReturnType ReturnType; + + static void push(lua_State* L, T& value) { Helper::push(L, value); } + + static ReturnType get(lua_State* L, int index) { return Helper::get(L, index); } +}; + +template +struct Stack +{ + typedef detail::StackOpSelector::value> Helper; + typedef typename Helper::ReturnType ReturnType; + + static void push(lua_State* L, const T& value) { Helper::push(L, value); } + + static ReturnType get(lua_State* L, int index) { return Helper::get(L, index); } +}; + +template +struct Stack +{ + typedef detail::StackOpSelector::value> Helper; + typedef typename Helper::ReturnType ReturnType; + + static void push(lua_State* L, T* value) { Helper::push(L, value); } + + static ReturnType get(lua_State* L, int index) { return Helper::get(L, index); } +}; + +template +struct Stack +{ + typedef detail::StackOpSelector::value> Helper; + typedef typename Helper::ReturnType ReturnType; + + static void push(lua_State* L, const T* value) { Helper::push(L, value); } + + static ReturnType get(lua_State* L, int index) { return Helper::get(L, index); } +}; + +//------------------------------------------------------------------------------ +/** + * Push an object onto the Lua stack. + */ +template +void push(lua_State* L, T t) +{ + Stack::push(L, t); +} + +//------------------------------------------------------------------------------ +/** + * Get an object from the Lua stack. + */ +template +T get(lua_State* L, int index) +{ + return Stack::get(L, index); +} + +//------------------------------------------------------------------------------ +/** + * Check whether an object on the Lua stack is of type T. + */ +template +bool isInstance(lua_State* L, int index) +{ + return Stack::isInstance(L, index); +} + +} // namespace luabridge diff --git a/csgo2/LuaBridge/luaBridge/detail/TypeList.h b/csgo2/LuaBridge/luaBridge/detail/TypeList.h new file mode 100644 index 0000000..781366a --- /dev/null +++ b/csgo2/LuaBridge/luaBridge/detail/TypeList.h @@ -0,0 +1,183 @@ +// https://github.com/vinniefalco/LuaBridge +// Copyright 2012, Vinnie Falco +// Copyright 2007, Nathan Reed +// SPDX-License-Identifier: MIT + +//============================================================================== +/* + This file incorporates work covered by the following copyright and + permission notice: + + The Loki Library + Copyright (c) 2001 by Andrei Alexandrescu + This code accompanies the book: + Alexandrescu, Andrei. "Modern C++ Design: Generic Programming and Design + Patterns Applied". Copyright (c) 2001. Addison-Wesley. + Permission to use, copy, modify, distribute and sell this software for any + purpose is hereby granted without fee, provided that the above copyright + notice appear in all copies and that both that copyright notice and this + permission notice appear in supporting documentation. + The author or Addison-Welsey Longman make no representations about the + suitability of this software for any purpose. It is provided "as is" + without express or implied warranty. +*/ +//============================================================================== + +#pragma once + +#include +#include + +#include +#include + +namespace luabridge { + +namespace detail { + +/** + None type means void parameters or return value. +*/ +typedef void None; + +template +struct TypeList +{ + typedef Tail TailType; +}; + +template +struct TypeListSize +{ + static const size_t value = TypeListSize::value + 1; +}; + +template<> +struct TypeListSize +{ + static const size_t value = 0; +}; + +template +struct MakeTypeList; + +template +struct MakeTypeList +{ + using Result = TypeList::Result>; +}; + +template<> +struct MakeTypeList<> +{ + using Result = None; +}; + +/** + A TypeList with actual values. +*/ +template +struct TypeListValues +{ + static std::string const tostring(bool) { return ""; } +}; + +/** + TypeListValues recursive template definition. +*/ +template +struct TypeListValues> +{ + Head hd; + TypeListValues tl; + + TypeListValues(Head hd_, TypeListValues const& tl_) : hd(hd_), tl(tl_) {} + + static std::string tostring(bool comma = false) + { + std::string s; + + if (comma) + s = ", "; + + s = s + typeid(Head).name(); + + return s + TypeListValues::tostring(true); + } +}; + +// Specializations of type/value list for head types that are references and +// const-references. We need to handle these specially since we can't count +// on the referenced object hanging around for the lifetime of the list. + +template +struct TypeListValues> +{ + Head hd; + TypeListValues tl; + + TypeListValues(Head& hd_, TypeListValues const& tl_) : hd(hd_), tl(tl_) {} + + static std::string const tostring(bool comma = false) + { + std::string s; + + if (comma) + s = ", "; + + s = s + typeid(Head).name() + "&"; + + return s + TypeListValues::tostring(true); + } +}; + +template +struct TypeListValues> +{ + Head hd; + TypeListValues tl; + + TypeListValues(Head const& hd_, const TypeListValues& tl_) : hd(hd_), tl(tl_) {} + + static std::string const tostring(bool comma = false) + { + std::string s; + + if (comma) + s = ", "; + + s = s + typeid(Head).name() + " const&"; + + return s + TypeListValues::tostring(true); + } +}; + +//============================================================================== +/** + Subclass of a TypeListValues constructable from the Lua stack. +*/ + +template +struct ArgList +{ +}; + +template +struct ArgList : public TypeListValues +{ + ArgList(lua_State*) {} +}; + +template +struct ArgList, Start> : public TypeListValues> +{ + ArgList(lua_State* L) + : TypeListValues>(Stack::get(L, Start), + ArgList(L)) + { + } +}; + +} // namespace detail + +} // namespace luabridge diff --git a/csgo2/LuaBridge/luaBridge/detail/TypeTraits.h b/csgo2/LuaBridge/luaBridge/detail/TypeTraits.h new file mode 100644 index 0000000..34b76dc --- /dev/null +++ b/csgo2/LuaBridge/luaBridge/detail/TypeTraits.h @@ -0,0 +1,112 @@ +// https://github.com/vinniefalco/LuaBridge +// Copyright 2019, Dmitry Tarakanov +// Copyright 2012, Vinnie Falco +// SPDX-License-Identifier: MIT + +#pragma once + +#include + +#include + +namespace luabridge { + +//------------------------------------------------------------------------------ +/** + Container traits. + + Unspecialized ContainerTraits has the isNotContainer typedef for SFINAE. + All user defined containers must supply an appropriate specialization for + ContinerTraits (without the typedef isNotContainer). The containers that + come with LuaBridge also come with the appropriate ContainerTraits + specialization. See the corresponding declaration for details. + + A specialization of ContainerTraits for some generic type ContainerType + looks like this: + + template + struct ContainerTraits > + { + typedef typename T Type; + + static T* get (ContainerType const& c) + { + return c.get (); // Implementation-dependent on ContainerType + } + }; +*/ +template +struct ContainerTraits +{ + typedef bool isNotContainer; + typedef T Type; +}; + +namespace detail { + +//------------------------------------------------------------------------------ +/** + Type traits. + + Specializations return information about a type. +*/ +struct TypeTraits +{ + /** Determine if type T is a container. + + To be considered a container, there must be a specialization of + ContainerTraits with the required fields. + */ + template + class isContainer + { + private: + typedef char yes[1]; // sizeof (yes) == 1 + typedef char no[2]; // sizeof (no) == 2 + + template + static no& test(typename C::isNotContainer*); + + template + static yes& test(...); + + public: + static const bool value = sizeof(test>(0)) == sizeof(yes); + }; + + /** Determine if T is const qualified. + */ + /** @{ */ + template + struct isConst + { + static bool const value = false; + }; + + template + struct isConst + { + static bool const value = true; + }; + /** @} */ + + /** Remove the const qualifier from T. + */ + /** @{ */ + template + struct removeConst + { + typedef T Type; + }; + + template + struct removeConst + { + typedef T Type; + }; + /**@}*/ +}; + +} // namespace detail + +} // namespace luabridge diff --git a/csgo2/LuaBridge/luaBridge/detail/Userdata.h b/csgo2/LuaBridge/luaBridge/detail/Userdata.h new file mode 100644 index 0000000..0d3912c --- /dev/null +++ b/csgo2/LuaBridge/luaBridge/detail/Userdata.h @@ -0,0 +1,769 @@ +// https://github.com/vinniefalco/LuaBridge +// Copyright 2019, Dmitry Tarakanov +// Copyright 2012, Vinnie Falco +// SPDX-License-Identifier: MIT + +#pragma once + +#include +#include + +#include +#include + +namespace luabridge { + +namespace detail { + +//============================================================================== +/** + Return the identity pointer for our lightuserdata tokens. + + Because of Lua's dynamic typing and our improvised system of imposing C++ + class structure, there is the possibility that executing scripts may + knowingly or unknowingly cause invalid data to get passed to the C functions + created by LuaBridge. In particular, our security model addresses the + following: + 1. Scripts cannot create a userdata (ignoring the debug lib). + 2. Scripts cannot create a lightuserdata (ignoring the debug lib). + 3. Scripts cannot set the metatable on a userdata. +*/ + +/** + Interface to a class pointer retrievable from a userdata. +*/ +class Userdata +{ +protected: + void* m_p; // subclasses must set this + + Userdata() : m_p(0) {} + + //-------------------------------------------------------------------------- + /** + Get an untyped pointer to the contained class. + */ + void* getPointer() { return m_p; } + +private: + //-------------------------------------------------------------------------- + /** + Validate and retrieve a Userdata on the stack. + + The Userdata must exactly match the corresponding class table or + const table, or else a Lua error is raised. This is used for the + __gc metamethod. + */ + static Userdata* getExactClass(lua_State* L, int index, void const* /*classKey*/) + { + return static_cast(lua_touserdata(L, lua_absindex(L, index))); + } + + //-------------------------------------------------------------------------- + /** + Validate and retrieve a Userdata on the stack. + + The Userdata must be derived from or the same as the given base class, + identified by the key. If canBeConst is false, generates an error if + the resulting Userdata represents to a const object. We do the type check + first so that the error message is informative. + */ + static Userdata* getClass(lua_State* L, + int index, + void const* registryConstKey, + void const* registryClassKey, + bool canBeConst) + { + index = lua_absindex(L, index); + + lua_getmetatable(L, index); // Stack: object metatable (ot) | nil + if (!lua_istable(L, -1)) + { + lua_rawgetp( + L, LUA_REGISTRYINDEX, registryClassKey); // Stack: registry metatable (rt) | nil + return throwBadArg(L, index); + } + + lua_rawgetp(L, -1, getConstKey()); // Stack: ot | nil, const table (co) | nil + assert(lua_istable(L, -1) || lua_isnil(L, -1)); + + // If const table is NOT present, object is const. Use non-const registry table + // if object cannot be const, so constness validation is done automatically. + // E.g. nonConstFn (constObj) + // -> canBeConst = false, isConst = true + // -> 'Class' registry table, 'const Class' object table + // -> 'expected Class, got const Class' + bool isConst = lua_isnil(L, -1); // Stack: ot | nil, nil, rt + if (isConst && canBeConst) + { + lua_rawgetp(L, LUA_REGISTRYINDEX, registryConstKey); // Stack: ot, nil, rt + } + else + { + lua_rawgetp(L, LUA_REGISTRYINDEX, registryClassKey); // Stack: ot, co, rt + } + + lua_insert(L, -3); // Stack: rt, ot, co | nil + lua_pop(L, 1); // Stack: rt, ot + + for (;;) + { + if (lua_rawequal(L, -1, -2)) // Stack: rt, ot + { + lua_pop(L, 2); // Stack: - + return static_cast(lua_touserdata(L, index)); + } + + // Replace current metatable with it's base class. + lua_rawgetp(L, -1, getParentKey()); // Stack: rt, ot, parent ot (pot) | nil + + if (lua_isnil(L, -1)) // Stack: rt, ot, nil + { + // Drop the object metatable because it may be some parent metatable + lua_pop(L, 2); // Stack: rt + return throwBadArg(L, index); + } + + lua_remove(L, -2); // Stack: rt, pot + } + + // no return + } + + static bool isInstance(lua_State* L, int index, void const* registryClassKey) + { + index = lua_absindex(L, index); + + int result = lua_getmetatable(L, index); // Stack: object metatable (ot) | nothing + if (result == 0) + { + return false; // Nothing was pushed on the stack + } + if (!lua_istable(L, -1)) + { + lua_pop(L, 1); // Stack: - + return false; + } + + lua_rawgetp(L, LUA_REGISTRYINDEX, registryClassKey); // Stack: ot, rt + lua_insert(L, -2); // Stack: rt, ot + + for (;;) + { + if (lua_rawequal(L, -1, -2)) // Stack: rt, ot + { + lua_pop(L, 2); // Stack: - + return true; + } + + // Replace current metatable with it's base class. + lua_rawgetp(L, -1, getParentKey()); // Stack: rt, ot, parent ot (pot) | nil + + if (lua_isnil(L, -1)) // Stack: rt, ot, nil + { + lua_pop(L, 3); // Stack: - + return false; + } + + lua_remove(L, -2); // Stack: rt, pot + } + } + + static Userdata* throwBadArg(lua_State* L, int index) + { + assert(lua_istable(L, -1) || lua_isnil(L, -1)); // Stack: rt | nil + + const char* expected = 0; + if (lua_isnil(L, -1)) // Stack: nil + { + expected = "unregistered class"; + } + else + { + lua_rawgetp(L, -1, getTypeKey()); // Stack: rt, registry type + expected = lua_tostring(L, -1); + } + + const char* got = 0; + if (lua_isuserdata(L, index)) + { + lua_getmetatable(L, index); // Stack: ..., ot | nil + if (lua_istable(L, -1)) // Stack: ..., ot + { + lua_rawgetp(L, -1, getTypeKey()); // Stack: ..., ot, object type | nil + if (lua_isstring(L, -1)) + { + got = lua_tostring(L, -1); + } + } + } + if (!got) + { + got = lua_typename(L, lua_type(L, index)); + } + + luaL_argerror(L, index, lua_pushfstring(L, "%s expected, got %s", expected, got)); + return 0; + } + +public: + virtual ~Userdata() {} + + //-------------------------------------------------------------------------- + /** + Returns the Userdata* if the class on the Lua stack matches. + If the class does not match, a Lua error is raised. + + @tparam T A registered user class. + @param L A Lua state. + @param index The index of an item on the Lua stack. + @returns A userdata pointer if the class matches. + */ + template + static Userdata* getExact(lua_State* L, int index) + { + return getExactClass(L, index, detail::getClassRegistryKey()); + } + + //-------------------------------------------------------------------------- + /** + Get a pointer to the class from the Lua stack. + If the object is not the class or a subclass, or it violates the + const-ness, a Lua error is raised. + + @tparam T A registered user class. + @param L A Lua state. + @param index The index of an item on the Lua stack. + @param canBeConst TBD + @returns A pointer if the class and constness match. + */ + template + static T* get(lua_State* L, int index, bool canBeConst) + { + if (lua_isnil(L, index)) + return 0; + + return static_cast(getClass(L, + index, + detail::getConstRegistryKey(), + detail::getClassRegistryKey(), + canBeConst) + ->getPointer()); + } + + template + static bool isInstance(lua_State* L, int index) + { + return isInstance(L, index, detail::getClassRegistryKey()); + } +}; + +//---------------------------------------------------------------------------- +/** + Wraps a class object stored in a Lua userdata. + + The lifetime of the object is managed by Lua. The object is constructed + inside the userdata using placement new. +*/ +template +class UserdataValue : public Userdata +{ +private: + UserdataValue(UserdataValue const&); + UserdataValue operator=(UserdataValue const&); + + char m_storage[sizeof(T)]; + +private: + /** + Used for placement construction. + */ + UserdataValue() { m_p = 0; } + + ~UserdataValue() + { + if (getPointer() != 0) + { + getObject()->~T(); + } + } + +public: + /** + Push a T via placement new. + + The caller is responsible for calling placement new using the + returned uninitialized storage. + + @param L A Lua state. + @returns An object referring to the newly created userdata value. + */ + static UserdataValue* place(lua_State* const L) + { + UserdataValue* const ud = + new (lua_newuserdata(L, sizeof(UserdataValue))) UserdataValue(); + lua_rawgetp(L, LUA_REGISTRYINDEX, detail::getClassRegistryKey()); + if (!lua_istable(L, -1)) + { + throw std::logic_error("The class is not registered in LuaBridge"); + } + lua_setmetatable(L, -2); + return ud; + } + + /** + Push T via copy construction from U. + + @tparam U A container type. + @param L A Lua state. + @param u A container object reference. + */ + template + static inline void push(lua_State* const L, U const& u) + { + UserdataValue* ud = place(L); + new (ud->getObject()) U(u); + ud->commit(); + } + + /** + Confirm object construction. + */ + void commit() { m_p = getObject(); } + + T* getObject() + { + // If this fails to compile it means you forgot to provide + // a Container specialization for your container! + // + return reinterpret_cast(&m_storage[0]); + } +}; + +//---------------------------------------------------------------------------- +/** + Wraps a pointer to a class object inside a Lua userdata. + + The lifetime of the object is managed by C++. +*/ +class UserdataPtr : public Userdata +{ +private: + UserdataPtr(UserdataPtr const&); + UserdataPtr operator=(UserdataPtr const&); + +private: + /** Push a pointer to object using metatable key. + */ + static void push(lua_State* L, const void* p, void const* const key) + { + new (lua_newuserdata(L, sizeof(UserdataPtr))) UserdataPtr(const_cast(p)); + lua_rawgetp(L, LUA_REGISTRYINDEX, key); + if (!lua_istable(L, -1)) + { + lua_pop(L, 1); // possibly: a nil + throw std::logic_error("The class is not registered in LuaBridge"); + } + lua_setmetatable(L, -2); + } + + explicit UserdataPtr(void* const p) + { + m_p = p; + + // Can't construct with a null pointer! + // + assert(m_p != 0); + } + +public: + /** Push non-const pointer to object. + + @tparam T A user registered class. + @param L A Lua state. + @param p A pointer to the user class instance. + */ + template + static void push(lua_State* const L, T* const p) + { + if (p) + push(L, p, getClassRegistryKey()); + else + lua_pushnil(L); + } + + /** Push const pointer to object. + + @tparam T A user registered class. + @param L A Lua state. + @param p A pointer to the user class instance. + */ + template + static void push(lua_State* const L, T const* const p) + { + if (p) + push(L, p, getConstRegistryKey()); + else + lua_pushnil(L); + } +}; + +//============================================================================ +/** + Wraps a container that references a class object. + + The template argument C is the container type, ContainerTraits must be + specialized on C or else a compile error will result. +*/ +template +class UserdataShared : public Userdata +{ +private: + UserdataShared(UserdataShared const&); + UserdataShared& operator=(UserdataShared const&); + + typedef typename TypeTraits::removeConst::Type>::Type T; + + C m_c; + +private: + ~UserdataShared() {} + +public: + /** + Construct from a container to the class or a derived class. + + @tparam U A container type. + @param u A container object reference. + */ + template + explicit UserdataShared(U const& u) : m_c(u) + { + m_p = const_cast(reinterpret_cast((ContainerTraits::get(m_c)))); + } + + /** + Construct from a pointer to the class or a derived class. + + @tparam U A container type. + @param u A container object pointer. + */ + template + explicit UserdataShared(U* u) : m_c(u) + { + m_p = const_cast(reinterpret_cast((ContainerTraits::get(m_c)))); + } +}; + +//---------------------------------------------------------------------------- +// +// SFINAE helpers. +// + +// non-const objects +template +struct UserdataSharedHelper +{ + typedef typename TypeTraits::removeConst::Type>::Type T; + + static void push(lua_State* L, C const& c) + { + if (ContainerTraits::get(c) != 0) + { + new (lua_newuserdata(L, sizeof(UserdataShared))) UserdataShared(c); + lua_rawgetp(L, LUA_REGISTRYINDEX, getClassRegistryKey()); + // If this goes off it means the class T is unregistered! + assert(lua_istable(L, -1)); + lua_setmetatable(L, -2); + } + else + { + lua_pushnil(L); + } + } + + static void push(lua_State* L, T* const t) + { + if (t) + { + new (lua_newuserdata(L, sizeof(UserdataShared))) UserdataShared(t); + lua_rawgetp(L, LUA_REGISTRYINDEX, getClassRegistryKey()); + // If this goes off it means the class T is unregistered! + assert(lua_istable(L, -1)); + lua_setmetatable(L, -2); + } + else + { + lua_pushnil(L); + } + } +}; + +// const objects +template +struct UserdataSharedHelper +{ + typedef typename TypeTraits::removeConst::Type>::Type T; + + static void push(lua_State* L, C const& c) + { + if (ContainerTraits::get(c) != 0) + { + new (lua_newuserdata(L, sizeof(UserdataShared))) UserdataShared(c); + lua_rawgetp(L, LUA_REGISTRYINDEX, getConstRegistryKey()); + // If this goes off it means the class T is unregistered! + assert(lua_istable(L, -1)); + lua_setmetatable(L, -2); + } + else + { + lua_pushnil(L); + } + } + + static void push(lua_State* L, T* const t) + { + if (t) + { + new (lua_newuserdata(L, sizeof(UserdataShared))) UserdataShared(t); + lua_rawgetp(L, LUA_REGISTRYINDEX, getConstRegistryKey()); + // If this goes off it means the class T is unregistered! + assert(lua_istable(L, -1)); + lua_setmetatable(L, -2); + } + else + { + lua_pushnil(L); + } + } +}; + +/** + Pass by container. + + The container controls the object lifetime. Typically this will be a + lifetime shared by C++ and Lua using a reference count. Because of type + erasure, containers like std::shared_ptr will not work. Containers must + either be of the intrusive variety, or in the style of the RefCountedPtr + type provided by LuaBridge (that uses a global hash table). +*/ +template +struct StackHelper +{ + static void push(lua_State* L, C const& c) + { + UserdataSharedHelper::Type>::value>:: + push(L, c); + } + + typedef typename TypeTraits::removeConst::Type>::Type T; + + static C get(lua_State* L, int index) { return Userdata::get(L, index, true); } +}; + +/** + Pass by value. + + Lifetime is managed by Lua. A C++ function which accesses a pointer or + reference to an object outside the activation record in which it was + retrieved may result in undefined behavior if Lua garbage collected it. +*/ +template +struct StackHelper +{ + static inline void push(lua_State* L, T const& t) { UserdataValue::push(L, t); } + + static inline T const& get(lua_State* L, int index) + { + return *Userdata::get(L, index, true); + } +}; + +//------------------------------------------------------------------------------ +/** + Lua stack conversions for pointers and references to class objects. + + Lifetime is managed by C++. Lua code which remembers a reference to the + value may result in undefined behavior if C++ destroys the object. The + handling of the const and volatile qualifiers happens in UserdataPtr. +*/ + +template +struct RefStackHelper +{ + typedef C return_type; + + static inline void push(lua_State* L, C const& t) + { + UserdataSharedHelper::Type>::value>:: + push(L, t); + } + + typedef typename TypeTraits::removeConst::Type>::Type T; + + static return_type get(lua_State* L, int index) { return Userdata::get(L, index, true); } +}; + +template +struct RefStackHelper +{ + typedef T& return_type; + + static void push(lua_State* L, T const& t) { UserdataPtr::push(L, &t); } + + static return_type get(lua_State* L, int index) + { + T* t = Userdata::get(L, index, true); + + if (!t) + luaL_error(L, "nil passed to reference"); + return *t; + } +}; + +/** + * Voider class template. Used to force a compiler to instantiate + * an otherwise probably unused template parameter type T. + * See the C++20 std::void_t <> for details. + */ +template +struct Void +{ + typedef void Type; +}; + +/** + * Trait class that selects whether to return a user registered + * class object by value or by reference. + */ + +template +struct UserdataGetter +{ + typedef T* ReturnType; + + static ReturnType get(lua_State* L, int index) { return Userdata::get(L, index, false); } +}; + +template +struct UserdataGetter::Type> +{ + typedef T ReturnType; + + static ReturnType get(lua_State* L, int index) + { + return StackHelper::value>::get(L, index); + } +}; + +} // namespace detail + +//============================================================================== + +/** + Lua stack conversions for class objects passed by value. +*/ +template +struct Stack +{ + typedef void IsUserdata; + + typedef detail::UserdataGetter Getter; + typedef typename Getter::ReturnType ReturnType; + + static void push(lua_State* L, T const& value) + { + using namespace detail; + StackHelper::value>::push(L, value); + } + + static ReturnType get(lua_State* L, int index) { return Getter::get(L, index); } + + static bool isInstance(lua_State* L, int index) + { + return detail::Userdata::isInstance(L, index); + } +}; + +namespace detail { + +/** + * Trait class indicating whether the parameter type must be + * a user registered class. The trait checks the existence of + * member type Stack::IsUserdata specialization for detection. + */ +template +struct IsUserdata +{ + static const bool value = false; +}; + +template +struct IsUserdata::IsUserdata>::Type> +{ + static const bool value = true; +}; + +/** + * Trait class that selects a specific push/get implementation. + */ +template +struct StackOpSelector; + +// pointer +template +struct StackOpSelector +{ + typedef T* ReturnType; + + static void push(lua_State* L, T* value) { UserdataPtr::push(L, value); } + + static T* get(lua_State* L, int index) { return Userdata::get(L, index, false); } + + static bool isInstance(lua_State* L, int index) { return Userdata::isInstance(L, index); } +}; + +// pointer to const +template +struct StackOpSelector +{ + typedef const T* ReturnType; + + static void push(lua_State* L, const T* value) { UserdataPtr::push(L, value); } + + static const T* get(lua_State* L, int index) { return Userdata::get(L, index, true); } + + static bool isInstance(lua_State* L, int index) { return Userdata::isInstance(L, index); } +}; + +// reference +template +struct StackOpSelector +{ + typedef RefStackHelper::value> Helper; + typedef typename Helper::return_type ReturnType; + + static void push(lua_State* L, T& value) { UserdataPtr::push(L, &value); } + + static ReturnType get(lua_State* L, int index) { return Helper::get(L, index); } + + static bool isInstance(lua_State* L, int index) { return Userdata::isInstance(L, index); } +}; + +// reference to const +template +struct StackOpSelector +{ + typedef RefStackHelper::value> Helper; + typedef typename Helper::return_type ReturnType; + + static void push(lua_State* L, const T& value) { Helper::push(L, value); } + + static ReturnType get(lua_State* L, int index) { return Helper::get(L, index); } + + static bool isInstance(lua_State* L, int index) { return Userdata::isInstance(L, index); } +}; + +} // namespace detail + +} // namespace luabridge diff --git a/csgo2/LuaBridge/luaBridge/detail/dump.h b/csgo2/LuaBridge/luaBridge/detail/dump.h new file mode 100644 index 0000000..e9ce000 --- /dev/null +++ b/csgo2/LuaBridge/luaBridge/detail/dump.h @@ -0,0 +1,125 @@ +// https://github.com/vinniefalco/LuaBridge +// Copyright 2019, Dmitry Tarakanov +// Copyright 2012, Vinnie Falco +// Copyright 2007, Nathan Reed +// SPDX-License-Identifier: MIT + +#pragma once + +#include "LuaBridge/detail/ClassInfo.h" + +#include +#include + +namespace luabridge { + +namespace debug { + +inline void putIndent(std::ostream& stream, unsigned level) +{ + for (unsigned i = 0; i < level; ++i) + { + stream << " "; + } +} + +inline void +dumpTable(lua_State* L, int index, std::ostream& stream, unsigned level, unsigned maxDepth); + +inline void +dumpValue(lua_State* L, int index, std::ostream& stream, unsigned maxDepth = 1, unsigned level = 0) +{ + const int type = lua_type(L, index); + switch (type) + { + case LUA_TNIL: + stream << "nil"; + break; + + case LUA_TBOOLEAN: + stream << (lua_toboolean(L, index) ? "true" : "false"); + break; + + case LUA_TNUMBER: + stream << lua_tonumber(L, index); + break; + + case LUA_TSTRING: + stream << '"' << lua_tostring(L, index) << '"'; + break; + + case LUA_TFUNCTION: + if (lua_iscfunction(L, index)) + { + stream << "cfunction@" << lua_topointer(L, index); + } + else + { + stream << "function@" << lua_topointer(L, index); + } + break; + + case LUA_TTHREAD: + stream << "thread@" << lua_tothread(L, index); + break; + + case LUA_TLIGHTUSERDATA: + stream << "lightuserdata@" << lua_touserdata(L, index); + break; + + case LUA_TTABLE: + dumpTable(L, index, stream, level, maxDepth); + break; + + case LUA_TUSERDATA: + stream << "userdata@" << lua_touserdata(L, index); + break; + + default: + stream << lua_typename(L, type); + ; + break; + } +} + +inline void +dumpTable(lua_State* L, int index, std::ostream& stream, unsigned level, unsigned maxDepth) +{ + stream << "table@" << lua_topointer(L, index); + + if (level > maxDepth) + { + return; + } + + index = lua_absindex(L, index); + stream << " {"; + lua_pushnil(L); // Initial key + while (lua_next(L, index)) + { + stream << "\n"; + putIndent(stream, level + 1); + dumpValue(L, -2, stream, maxDepth, level + 1); // Key + stream << ": "; + dumpValue(L, -1, stream, maxDepth, level + 1); // Value + lua_pop(L, 1); // Value + } + stream << "\n"; + putIndent(stream, level); + stream << "}"; +} + +inline void dumpState(lua_State* L, std::ostream& stream = std::cerr, unsigned maxDepth = 1) +{ + int top = lua_gettop(L); + for (int i = 1; i <= top; ++i) + { + stream << "stack #" << i << ": "; + dumpValue(L, i, stream, maxDepth, 0); + stream << "\n"; + } +} + +} // namespace debug + +} // namespace luabridge diff --git a/csgo2/csgo2.vcxproj b/csgo2/csgo2.vcxproj index 285337a..14f57d5 100644 --- a/csgo2/csgo2.vcxproj +++ b/csgo2/csgo2.vcxproj @@ -78,11 +78,11 @@ true - F:\source2\csgo2\csgo2\sdk\protobuf-2.6.1\src;$(IncludePath) + $(MSBuildProjectDirectory)\sdk\protobuf-2.6.1\src;$(MSBuildProjectDirectory)\LuaBridge;$(IncludePath) false - F:\source2\csgo2\csgo2\sdk\protobuf-2.6.1\src;$(IncludePath) + $(MSBuildProjectDirectory)\sdk\protobuf-2.6.1\src;$(MSBuildProjectDirectory)\LuaBridge;$(IncludePath) @@ -213,16 +213,25 @@ + + + + + + + + + diff --git a/csgo2/csgo2.vcxproj.filters b/csgo2/csgo2.vcxproj.filters index 3257372..907a65b 100644 --- a/csgo2/csgo2.vcxproj.filters +++ b/csgo2/csgo2.vcxproj.filters @@ -291,6 +291,33 @@ 头文件\script_engine + + 头文件\sdk\tier1 + + + 头文件\sdk\public + + + 头文件\sdk\public + + + 头文件\sdk\public + + + 头文件\sdk\tier1 + + + 头文件\sdk\tier1 + + + 头文件\sdk\tier1 + + + 头文件\sdk\public + + + 头文件\native_sdk + diff --git a/csgo2/events.cpp b/csgo2/events.cpp index 49917c6..8990846 100644 --- a/csgo2/events.cpp +++ b/csgo2/events.cpp @@ -4,9 +4,10 @@ namespace events { auto OnPlayerDeathEvent(IGameEvent* event) -> void { UnkGameEventStruct_t userIdNameParams{"userid"}; UnkGameEventStruct_t attackerNameParams{"attacker"}; - UnkGameEventStruct_t headshotNameParams{ 0 }; + UnkGameEventStruct_t headshotNameParams{0}; static const auto headShotStr = "headshot"; - headshotNameParams.m_Unk = Offset::FnServerHashFunction(headShotStr, sizeof headShotStr, SERVER_HASH_FUCNTION_KEY); + headshotNameParams.m_Unk = Offset::FnServerHashFunction( + headShotStr, sizeof headShotStr, SERVER_HASH_FUCNTION_KEY); headshotNameParams.m_Key = headShotStr; const auto victimPawn = reinterpret_cast( event->GetPlayerPawn(&userIdNameParams)); @@ -25,10 +26,9 @@ auto OnPlayerDeathEvent(IGameEvent* event) -> void { if (victim == nullptr || attacker == nullptr) { return; } - const auto victimIndex = victim->GetRefEHandle().m_Index; - const auto attackerIndex = attacker->GetRefEHandle().m_Index; - LOG("is head shot: %d \n", isHeadShot); - ScriptCallBacks::luaCall_onPlayerDeath(victimIndex, attackerIndex); + const auto victimIndex = victim->GetRefEHandle().GetEntryIndex(); + const auto attackerIndex = attacker->GetRefEHandle().GetEntryIndex(); + ScriptCallBacks::luaCall_onPlayerDeath(victimIndex, attackerIndex, isHeadShot); // printf("player[%p] %s kill[%p] %llu\n", attacker, // &attacker->m_iszPlayerName(), victim, &victim->m_steamID()); } diff --git a/csgo2/head.h b/csgo2/head.h index ae87c81..474ad4f 100644 --- a/csgo2/head.h +++ b/csgo2/head.h @@ -32,23 +32,33 @@ static void DebugPrintA(const char* format, ...) { #include "./MinHook/include/MinHook.h" #include "hash_fnv1a_constexpr.h" // ¹¤¾ß¿â - +#include "vector.h" #include "vmt.h" #include "memory.h" + +// sdk #include "sdk/gameevent/IGameEvent.h" #include "sdk/tier1/bufferstring.h" #include "sdk/public/eiface.h" #include "sdk/player/playerslot.h" -// sdk #include "sdk/sdk.h" +#include "sdk/public/mathlib.h" +#include "sdk/public/string_t.h" +#include "sdk/tier1/UtlMemory.hpp" +#include "sdk/tier1/utlfixedmemory.h" +#include "sdk/tier1/utlblockmemory.h" #include "sdk/tier1/UtlString.hpp" #include "sdk/interfaces/interfaces.h" #include "sdk/public/eiface.h" #include "sdk/gameevent/IGameEvent.h" #include "sdk/convar/convar.hpp" #include "sdk/tier1/bufferstring.h" +#include "sdk/public/bitvec.h" +#include "sdk/public/iserver.h" +#include "sdk/public/utlrbtree.h" +#include "sdk/public/utlmap.h" #include "offset.h" #include "native_sdk.h" @@ -64,6 +74,7 @@ static void DebugPrintA(const char* format, ...) { #include "sdk_tools.h" #include "lua/lua.hpp" +#include "LuaBridge/LuaBridge.h" #include "tools.h" #include "script_engine.h" #include "script_apis.h" diff --git a/csgo2/native_sdk.cpp b/csgo2/native_sdk.cpp index d8b37a7..180f51b 100644 --- a/csgo2/native_sdk.cpp +++ b/csgo2/native_sdk.cpp @@ -53,18 +53,35 @@ auto CCSPlayerPawn::GetPlayerController() -> CCSPlayerController* return nullptr; } -using SchemaKeyValueMap_t = std::unordered_map; -using SchemaTableMap_t = std::unordered_map; +using SchemaKeyValueMap_t = CUtlMap; +using SchemaTableMap_t = CUtlMap; -static bool InitSchemaFieldsForClass(SchemaTableMap_t& tableMap, - const char* className, uint32_t classKey) { - CSchemaSystemTypeScope* pType = - Offset::InterFaces::SchemaSystem->FindTypeScopeForModule("server.dll"); - if (!pType) return false; + +static bool IsFieldNetworked(SchemaClassFieldData_t& field) +{ + for (int i = 0; i < field.m_metadata_size; i++) + { + static auto networkEnabled = hash_32_fnv1a_const("MNetworkEnable"); + if (networkEnabled == hash_32_fnv1a_const(field.m_metadata[i].m_name)) + return true; + } + + return false; +} + +static bool InitSchemaFieldsForClass(SchemaTableMap_t* tableMap, const char* className, uint32_t classKey) +{ + CSchemaSystemTypeScope* pType = Offset::InterFaces::SchemaSystem->FindTypeScopeForModule("server.dll"); + + if (!pType) + return false; SchemaClassInfoData_t* pClassInfo = pType->FindDeclaredClass(className); - if (!pClassInfo) { - tableMap.emplace(classKey, SchemaKeyValueMap_t{}); + + if (!pClassInfo) + { + SchemaKeyValueMap_t* map = new SchemaKeyValueMap_t(0, 0, DefLessFunc(uint32_t)); + tableMap->Insert(classKey, map); LOG("InitSchemaFieldsForClass(): '%s' was not found!\n", className); return false; @@ -73,14 +90,15 @@ static bool InitSchemaFieldsForClass(SchemaTableMap_t& tableMap, short fieldsSize = pClassInfo->GetFieldsSize(); SchemaClassFieldData_t* pFields = pClassInfo->GetFields(); - auto& keyValueMap = tableMap[classKey]; - keyValueMap.reserve(fieldsSize); + SchemaKeyValueMap_t* keyValueMap = new SchemaKeyValueMap_t(0, 0, DefLessFunc(uint32_t)); + keyValueMap->EnsureCapacity(fieldsSize); + tableMap->Insert(classKey, keyValueMap); - for (int i = 0; i < fieldsSize; ++i) { + for (int i = 0; i < fieldsSize; ++i) + { SchemaClassFieldData_t& field = pFields[i]; - LOG("%s::%s found at -> 0x%X\n", className, field.m_name, - field.m_offset); - keyValueMap.emplace(hash_32_fnv1a_const(field.m_name), field.m_offset); + + keyValueMap->Insert(hash_32_fnv1a_const(field.m_name), { field.m_offset, IsFieldNetworked(field) }); } return true; @@ -88,9 +106,11 @@ static bool InitSchemaFieldsForClass(SchemaTableMap_t& tableMap, int16_t schema::FindChainOffset(const char* className) { - CSchemaSystemTypeScope* pType = - Offset::InterFaces::SchemaSystem->FindTypeScopeForModule("server.dll"); - if (!pType) return false; + + CSchemaSystemTypeScope* pType = Offset::InterFaces::SchemaSystem->FindTypeScopeForModule("server.dll"); + + if (!pType) + return false; SchemaClassInfoData_t* pClassInfo = pType->FindDeclaredClass(className); @@ -98,36 +118,86 @@ int16_t schema::FindChainOffset(const char* className) { SchemaClassFieldData_t* pFields = pClassInfo->GetFields(); short fieldsSize = pClassInfo->GetFieldsSize(); - for (int i = 0; i < fieldsSize; ++i) { + for (int i = 0; i < fieldsSize; ++i) + { SchemaClassFieldData_t& field = pFields[i]; if (strcmp(field.m_name, "__m_pChainEntity") == 0) { return field.m_offset; } - } } while ((pClassInfo = pClassInfo->GetParent()) != nullptr); return 0; } -int16_t schema::GetOffset(const char* className, uint32_t classKey, - const char* memberName, uint32_t memberKey) { - static SchemaTableMap_t schemaTableMap; - const auto& tableMapIt = schemaTableMap.find(classKey); - if (tableMapIt == schemaTableMap.cend()) { - if (InitSchemaFieldsForClass(schemaTableMap, className, classKey)) +SchemaKey schema::GetOffset(const char* className, uint32_t classKey, const char* memberName, uint32_t memberKey) +{ + static SchemaTableMap_t schemaTableMap(0, 0, DefLessFunc(uint32_t)); + int16_t tableMapIndex = schemaTableMap.Find(classKey); + if (!schemaTableMap.IsValidIndex(tableMapIndex)) + { + if (InitSchemaFieldsForClass(&schemaTableMap, className, classKey)) return GetOffset(className, classKey, memberName, memberKey); - return 0; + + return { 0, 0 }; } - const SchemaKeyValueMap_t& tableMap = tableMapIt->second; - if (tableMap.find(memberKey) == tableMap.cend()) { + SchemaKeyValueMap_t* tableMap = schemaTableMap[tableMapIndex]; + int16_t memberIndex = tableMap->Find(memberKey); + if (!tableMap->IsValidIndex(memberIndex)) + { LOG("schema::GetOffset(): '%s' was not found in '%s'!\n", memberName, className); - - return 0; + return { 0, 0 }; } - return tableMap.at(memberKey); -} \ No newline at end of file + return tableMap->Element(memberIndex); +} + +bool CEconItemDefinition::IsWeapon() { + // Every gun supports at least 4 stickers. + return GetStickersSupportedCount() >= 4; +} + +bool CEconItemDefinition::IsKnife(bool excludeDefault) { + static constexpr auto CSGO_Type_Knife = + hash_32_fnv1a_const("#CSGO_Type_Knife"); + + if (hash_32_fnv1a_const(m_pszItemTypeName) != CSGO_Type_Knife) return false; + return excludeDefault ? m_nDefIndex >= 500 : true; +} + +bool CEconItemDefinition::IsGlove(bool excludeDefault) { + static constexpr auto Type_Hands = hash_32_fnv1a_const("#Type_Hands"); + + if (hash_32_fnv1a_const(m_pszItemTypeName) != Type_Hands) return false; + const bool defaultGlove = m_nDefIndex == 5028 || m_nDefIndex == 5029; + + return excludeDefault ? !defaultGlove : true; +} + +auto CLocalize::FindSafe(const char* tokenName) -> const char* +{ + return CALL_VIRTUAL(const char*, 17, this, tokenName); +} +auto GetGameGlobals() -> CGlobalVars* +{ + INetworkGameServer* server = Offset::InterFaces::INetworkServerServiceInteFace->GetIGameServer(); + + if (!server) + return nullptr; + + return Offset::InterFaces::INetworkServerServiceInteFace->GetIGameServer()->GetGlobals(); +} + +auto SetStateChanged(Z_CBaseEntity* pEntity, int offset) -> void +{ + Offset::FnStateChanged(pEntity->m_NetworkTransmitComponent(), pEntity, offset, -1, -1); + auto vars = GetGameGlobals(); + + if (vars) + pEntity->m_lastNetworkChange(vars->curtime); + + pEntity->m_isSteadyState(0); +}; diff --git a/csgo2/native_sdk.h b/csgo2/native_sdk.h index c748177..2a991e5 100644 --- a/csgo2/native_sdk.h +++ b/csgo2/native_sdk.h @@ -1,80 +1,129 @@ #pragma once #include "head.h" +class CEntityInstance; +typedef void(__fastcall* StateChanged_t)(void* networkTransmitComponent, CEntityInstance* ent, uint64_t offset, int a4, int a5); +typedef void(__fastcall* NetworkStateChanged_t)(uintptr_t chainEntity, uintptr_t offset, uintptr_t a3); namespace Offset { - extern uint64_t NetworkStateChangedPtr; + extern StateChanged_t FnStateChanged; + extern NetworkStateChanged_t FnNetworkStateChanged; } -#define DECLARE_CLASS(className) static constexpr auto ThisClass = #className; +struct SchemaKey { + int16_t offset; + bool networked; +}; +class Z_CBaseEntity; +extern auto SetStateChanged(Z_CBaseEntity* pEntity, int offset) -> void; #define MAX_ENTITIES_IN_LIST 512 #define MAX_ENTITY_LISTS 64 #define MAX_TOTAL_ENTITIES MAX_ENTITIES_IN_LIST *MAX_ENTITY_LISTS #define INVALID_EHANDLE_INDEX 0xFFFFFFFF #define ENT_ENTRY_MASK 0x7FFF -#define SCHEMA_FIELD_OFFSET(type, varName, extra_offset) \ - std::add_lvalue_reference_t varName() \ - { \ - static constexpr auto datatable_hash = hash_32_fnv1a_const(ThisClass); \ - static constexpr auto prop_hash = hash_32_fnv1a_const(#varName); \ - \ - static const auto m_offset = \ - schema::GetOffset(ThisClass, datatable_hash, #varName, prop_hash); \ - \ - return *reinterpret_cast>( \ - (uintptr_t)(this) + m_offset + extra_offset); \ - } \ - void varName(type val) \ - { \ - static constexpr auto datatable_hash = hash_32_fnv1a_const(ThisClass); \ - static constexpr auto prop_hash = hash_32_fnv1a_const(#varName); \ - \ - static const auto m_offset = \ - schema::GetOffset(ThisClass, datatable_hash, #varName, prop_hash); \ - \ - static const auto m_chain = \ - schema::FindChainOffset(ThisClass); \ - \ - if (m_chain != 0) \ - { \ - reinterpret_cast(Offset::NetworkStateChangedPtr)((uintptr_t)(this) + m_chain, m_offset + extra_offset, 0xFFFFFFFF); \ - } \ - *reinterpret_cast>((uintptr_t)(this) + m_offset + extra_offset) = val; \ - } + +#define DECLARE_SCHEMA_CLASS_BASE(className, isStruct) \ + static constexpr const char *ThisClass = #className; \ + static constexpr bool OffsetIsStruct = isStruct; + +#define DECLARE_CLASS(className) DECLARE_SCHEMA_CLASS_BASE(className, false) + +// Use this for classes that can be wholly included within other classes (like CCollisionProperty within CBaseModelEntity) +#define DECLARE_SCHEMA_CLASS_INLINE(className) \ + DECLARE_SCHEMA_CLASS_BASE(className, true) + +#define SCHEMA_FIELD_OFFSET(type, varName, extra_offset) \ + std::add_lvalue_reference_t varName() \ + { \ + static constexpr auto datatable_hash = hash_32_fnv1a_const(ThisClass); \ + static constexpr auto prop_hash = hash_32_fnv1a_const(#varName); \ + \ + static const auto m_key = \ + schema::GetOffset(ThisClass, datatable_hash, #varName, prop_hash); \ + \ + return *reinterpret_cast>( \ + (uintptr_t)(this) + m_key.offset + extra_offset); \ + } \ + void varName(type val) \ + { \ + static constexpr auto datatable_hash = hash_32_fnv1a_const(ThisClass); \ + static constexpr auto prop_hash = hash_32_fnv1a_const(#varName); \ + \ + static const auto m_key = \ + schema::GetOffset(ThisClass, datatable_hash, #varName, prop_hash); \ + \ + static const auto m_chain = \ + schema::FindChainOffset(ThisClass); \ + \ + if (m_chain != 0 && m_key.networked) \ + { \ + LOG("Found chain offset %d for %s::%s\n", m_chain, ThisClass, #varName); \ + Offset::FnNetworkStateChanged((uintptr_t)(this) + m_chain, m_key.offset + extra_offset, 0xFFFFFFFF); \ + } \ + else if(m_key.networked) \ + { \ + /* WIP: Works fine for most props, but inlined classes in the middle of a class will + need to have their this pointer corrected by the offset .*/ \ + LOG("Attempting to call SetStateChanged on on %s::%s\n", ThisClass, #varName); \ + if (!OffsetIsStruct) \ + SetStateChanged((Z_CBaseEntity*)this, m_key.offset + extra_offset); \ + else \ + CALL_VIRTUAL(void, 1, this, m_key.offset + extra_offset, 0xFFFFFFFF, 0xFFFF); \ + \ + } \ + * reinterpret_cast>((uintptr_t)(this) + m_key.offset + extra_offset) = val; \ +} #define SCHEMA_FIELD(type, varName) \ SCHEMA_FIELD_OFFSET(type, varName, 0) + #define PSCHEMA_FIELD_OFFSET(type, varName, extra_offset) \ auto varName() \ { \ static constexpr auto datatable_hash = hash_32_fnv1a_const(ThisClass); \ static constexpr auto prop_hash = hash_32_fnv1a_const(#varName); \ \ - static const auto m_offset = \ + static const auto m_key = \ schema::GetOffset(ThisClass, datatable_hash, #varName, prop_hash); \ \ return reinterpret_cast>( \ - (uintptr_t)(this) + m_offset + extra_offset); \ + (uintptr_t)(this) + m_key.offset + extra_offset); \ } #define PSCHEMA_FIELD(type, varName) \ PSCHEMA_FIELD_OFFSET(type, varName, 0) -typedef void(__fastcall* FnNetworkStateChanged)(uintptr_t chainEntity, uintptr_t offset, uintptr_t a3); + + namespace schema { int16_t FindChainOffset(const char* className); - int16_t GetOffset(const char* className, uint32_t classKey, const char* memberName, uint32_t memberKey); + SchemaKey GetOffset(const char* className, uint32_t classKey, const char* memberName, uint32_t memberKey); } +struct CSchemaNetworkValue { + union { + const char* m_sz_value; + int m_n_value; + float m_f_value; + std::uintptr_t m_p_value; + }; +}; + +struct SchemaMetadataEntryData_t { + const char* m_name; + CSchemaNetworkValue* m_value; +}; struct SchemaClassFieldData_t { const char* m_name; char pad0[0x8]; short m_offset; - char pad1[0xE]; + int32_t m_metadata_size; + SchemaMetadataEntryData_t* m_metadata; }; + class SchemaClassInfoData_t; struct SchemaBaseClassInfoData_t @@ -101,8 +150,11 @@ public: return m_fields; } - auto GetParent() + auto GetParent() -> SchemaClassInfoData_t* { + if (!m_schema_parent) + return nullptr; + return m_schema_parent->m_class; } @@ -132,15 +184,35 @@ private: class CSchemaSystemTypeScope { public: - auto FindDeclaredClass(const char* pClass)->SchemaClassInfoData_t*; + auto FindDeclaredClass(const char* pClass) -> SchemaClassInfoData_t*; }; class CSchemaSystem { public: - auto FindTypeScopeForModule(const char* module)->CSchemaSystemTypeScope*; + auto FindTypeScopeForModule(const char* module) -> CSchemaSystemTypeScope*; }; +template +class CUtlVector_NativeSdk { +public: + auto begin() const { return m_data; } + auto end() const { return m_data + m_size; } + + bool Exists(T val) const { + for (const auto& it : *this) + if (it == val) return true; + return false; + } + bool Empty() const { return m_size == 0; } + + int m_size; + char pad0[0x4]; // no idea + T* m_data; + char pad1[0x8]; // no idea +}; + + class CBaseEntity; class CEntityIdentity { @@ -211,9 +283,9 @@ public: DECLARE_CLASS(CCollisionProperty) SCHEMA_FIELD(VPhysicsCollisionAttribute_t, m_collisionAttribute) - //SCHEMA_FIELD(SolidType_t, m_nSolidType) - SCHEMA_FIELD(uint8_t, m_usSolidFlags) - SCHEMA_FIELD(uint8_t, m_CollisionGroup) + //SCHEMA_FIELD(SolidType_t, m_nSolidType) + SCHEMA_FIELD(uint8_t, m_usSolidFlags) + SCHEMA_FIELD(uint8_t, m_CollisionGroup) }; class CHandle @@ -290,6 +362,92 @@ public: SCHEMA_FIELD(const char*, m_szClanName) }; +class CEconItemDefinition { +public: + bool IsWeapon(); + bool IsKnife(bool excludeDefault); + bool IsGlove(bool excludeDefault); + + auto GetModelName() { + return *reinterpret_cast((uintptr_t)(this) + 0xD8); + } + + auto GetStickersSupportedCount() { + return *reinterpret_cast((uintptr_t)(this) + 0x100); + } + + auto GetSimpleWeaponName() { + return *reinterpret_cast((uintptr_t)(this) + 0x210); + } + + auto GetLoadoutSlot() { + return *reinterpret_cast((uintptr_t)(this) + 0x2E8); + } + + char pad0[0x8]; // vtable + void* m_pKVItem; + uint16_t m_nDefIndex; + CUtlVector_NativeSdk m_nAssociatedItemsDefIndexes; + bool m_bEnabled; + const char* m_szPrefab; + uint8_t m_unMinItemLevel; + uint8_t m_unMaxItemLevel; + uint8_t m_nItemRarity; + uint8_t m_nItemQuality; + uint8_t m_nForcedItemQuality; + uint8_t m_nDefaultDropItemQuality; + uint8_t m_nDefaultDropQuantity; + CUtlVector_NativeSdk m_vecStaticAttributes; + uint8_t m_nPopularitySeed; + void* m_pPortraitsKV; + const char* m_pszItemBaseName; + bool m_bProperName; + const char* m_pszItemTypeName; + uint32_t m_unItemTypeID; + const char* m_pszItemDesc; +}; + +class CEconItemView { +public: + DECLARE_CLASS(CEconItemView); + auto GetCustomPaintKitIndex() { return CALL_VIRTUAL(int, 2, this); } + auto GetStaticData() { + return CALL_VIRTUAL(CEconItemDefinition*, 13, this); + } +}; +class CAttributeContainer +{ +public: + DECLARE_CLASS(CAttributeContainer); + + PSCHEMA_FIELD(CEconItemView, m_Item); +}; +class CEconEntity { +public: + DECLARE_CLASS(CEconEntity); + + PSCHEMA_FIELD(CAttributeContainer, m_AttributeManager); +}; + +class CBasePlayerWeapon : public CEconEntity +{ +public: + DECLARE_CLASS(CBasePlayerWeapon); + + SCHEMA_FIELD(int, m_iClip1); + SCHEMA_FIELD(int, m_iClip2); + SCHEMA_FIELD(int, m_pReserveAmmo); +}; + +class CPlayer_WeaponServices { +public: + DECLARE_CLASS(CPlayer_WeaponServices) + + SCHEMA_FIELD(CHandle, m_hActiveWeapon); + SCHEMA_FIELD(uint16_t, m_iAmmo); + +}; + class CBasePlayer { public: @@ -312,7 +470,7 @@ public: DECLARE_CLASS(CBasePlayerPawn); SCHEMA_FIELD(CPlayer_MovementServices*, m_pMovementServices) - SCHEMA_FIELD(uint8_t*, m_pWeaponServices) + SCHEMA_FIELD(CPlayer_WeaponServices*, m_pWeaponServices) SCHEMA_FIELD(uint8_t**, m_pItemServices) }; class CCSPlayerPawn : public CBasePlayerPawn { @@ -331,4 +489,23 @@ public: { return *reinterpret_cast((uintptr_t)(this) + 0x58); } -}; \ No newline at end of file +}; + +class CLocalize { +public: + auto FindSafe(const char* tokenName) -> const char*; +}; + +class Z_CBaseEntity : public CBaseEntity +{ +public: + DECLARE_CLASS(CBaseEntity) + + SCHEMA_FIELD(CBitVec<64>, m_isSteadyState) + SCHEMA_FIELD(float, m_lastNetworkChange) + PSCHEMA_FIELD(void*, m_NetworkTransmitComponent) + SCHEMA_FIELD(int, m_iHealth) + SCHEMA_FIELD(int, m_iTeamNum) + SCHEMA_FIELD(Vector, m_vecBaseVelocity) + SCHEMA_FIELD(CCollisionProperty*, m_pCollision) +}; diff --git a/csgo2/offset.cpp b/csgo2/offset.cpp index 2234980..4a8937d 100644 --- a/csgo2/offset.cpp +++ b/csgo2/offset.cpp @@ -3,12 +3,13 @@ namespace Offset { uint64_t GameResourceServicePtr; uint64_t FireEventServerSidePtr; -uint64_t NetworkStateChangedPtr; uint64_t CGameEventManagerPtr; uint64_t Host_SayPtr; uint64_t Module_tier0; uint64_t MaxPlayerNumsPtr; HashFunction_t FnServerHashFunction; +StateChanged_t FnStateChanged; +NetworkStateChanged_t FnNetworkStateChanged; namespace InterFaces { CSchemaSystem* SchemaSystem; IGameEventManager2* GameEventManager; @@ -17,39 +18,41 @@ CGameResourceService* GameResourceServiceServer; IServerGameClients* IServerGameClient; IVEngineServer2* IVEngineServer; ISource2Server* ISource2ServerInterFace; +CLocalize* ILocalize; +INetworkServerService* INetworkServerServiceInteFace; }; // namespace InterFaces auto Init() -> bool { CModule server("server.dll"); CModule schemasystem("schemasystem.dll"); CModule engine("engine2.dll"); + CModule localize("localize.dll"); + // engine.dll engine.FindPattern(pattern_MaxPlayerNumsPtr).ToAbsolute(3, 0).Get(MaxPlayerNumsPtr); // server.dll server.FindPattern(pattern_FireEventServerSide).Get(FireEventServerSidePtr); - server.FindPattern(pattern_NetworkStateChanged).Get(NetworkStateChangedPtr); + server.FindPattern(pattern_NetworkStateChanged).Get(FnNetworkStateChanged); + server.FindPattern(pattern_FnStateChangedPtr).Get(FnStateChanged); + // 48 8D 05 4A 30 82 00 lea rax, ??_7CGameEventManager@@6B@ server.FindPattern(pattern_CGameEventManager) .ToAbsolute(3, 0) .Get(CGameEventManagerPtr); server.FindPattern(pattern_fnHost_SayPtr).Get(Host_SayPtr); server.FindPattern(pattern_ServerHashFunctionPtr).Get(FnServerHashFunction); - - // schemasystem InterFaces::SchemaSystem = reinterpret_cast( schemasystem.FindInterface("SchemaSystem_001").Get()); - - // engine.dll //InterFaces::GameEventManager = reinterpret_cast( // engine.FindInterface("GameEventSystemServerV001").Get()); - //InterFaces::GameEventManager = reinterpret_cast(engine.FindInterface("GameEventSystemServerV001").Get()); + InterFaces::ILocalize = reinterpret_cast(localize.FindInterface("Localize_001").Get()); InterFaces::GameResourceServiceServer = reinterpret_cast( engine.FindInterface("GameResourceServiceServerV001").Get()); InterFaces::IVEngineServer = reinterpret_cast( engine.FindInterface("Source2EngineToServer001").Get()); - - // server.dll + InterFaces::INetworkServerServiceInteFace = reinterpret_cast( + engine.FindInterface("NetworkServerService_001").Get()); InterFaces::IServerGameClient = reinterpret_cast( server.FindInterface("Source2GameClients001").Get()); InterFaces::ISource2ServerInterFace = reinterpret_cast( @@ -65,9 +68,10 @@ auto Init() -> bool { global::MaxPlayers = 64; LOG("[huoji]FireEventServerSidePtr : %llx \n", FireEventServerSidePtr); - LOG("[huoji]NetworkStateChangedPtr : %llx \n", NetworkStateChangedPtr); LOG("[huoji]Host_SayPtr : %llx \n", Host_SayPtr); + LOG("[huoji]FnNetworkStateChanged : %llx \n", FnNetworkStateChanged); LOG("[huoji]FnServerHashFunction : %llx \n", FnServerHashFunction); + LOG("[huoji]FnStateChanged : %llx \n", FnStateChanged); LOG("[huoji]MaxGlobals : %d \n", global::MaxPlayers); LOG("[huoji]InterFaces::SchemaSystem : %llx \n", InterFaces::SchemaSystem); @@ -86,11 +90,11 @@ auto Init() -> bool { // GetOffsets(); LOG("init offset success !\n"); - LOG("FnServerHashFunction: %llx \n", FnServerHashFunction("here", sizeof("here") - 1, 0x31415926)); + //LOG("FnServerHashFunction: %llx \n", FnServerHashFunction("here", sizeof("here") - 1, 0x31415926)); return FnServerHashFunction && Host_SayPtr && InterFaces::IVEngineServer && InterFaces::GameResourceServiceServer && InterFaces::IServerGameClient && InterFaces::GameEventManager && InterFaces::SchemaSystem && FireEventServerSidePtr && - NetworkStateChangedPtr; + FnNetworkStateChanged; } } // namespace Offset diff --git a/csgo2/offset.h b/csgo2/offset.h index 576adaa..17e9dc5 100644 --- a/csgo2/offset.h +++ b/csgo2/offset.h @@ -1,10 +1,14 @@ #pragma once #include "head.h" #define SERVER_HASH_FUCNTION_KEY 0x31415926 +class CEntityInstance; typedef uint64_t(__fastcall* HashFunction_t)(const char*, unsigned int, unsigned int); +typedef void(__fastcall* StateChanged_t)(void* networkTransmitComponent, CEntityInstance* ent, uint64_t offset, int a4, int a5); +typedef void(__fastcall* NetworkStateChanged_t)(uintptr_t chainEntity, uintptr_t offset, uintptr_t a3); class CSchemaSystem; class CGameResourceService; +class CLocalize; namespace Offset { namespace InterFaces { extern CSchemaSystem* SchemaSystem; @@ -13,9 +17,12 @@ namespace InterFaces { extern CGameResourceService* GameResourceServiceServer; extern IServerGameClients* IServerGameClient; extern IVEngineServer2* IVEngineServer; + extern CLocalize* ILocalize; + extern INetworkServerService* INetworkServerServiceInteFace; }; static const auto pattern_CGameEventManager = THE_GAME_SIG("48 ?? ?? ?? ?? ?? ?? 48 89 ?? ?? ?? 48 89 01 48 8B D9 48 ?? ?? ?? ?? ?? ?? 48 89 ?? ?? E8 ?? ?? ?? ?? 48 ?? ?? ?? ?? ?? ??"); static const auto pattern_NetworkStateChanged = THE_GAME_SIG("4C 8B C9 48 8B 09 48 85 C9 74 ? 48 8B 41 10"); +static const auto pattern_FnStateChangedPtr = THE_GAME_SIG("48 89 54 24 10 55 53 57 41 55"); static const auto pattern_FireEventServerSide = THE_GAME_SIG( "40 53 57 41 54 41 55 41 56 48 ?? ?? ?? 4C 8B F2 4C 8B E1 BA ?? ?? ?? " "?? 48 ?? ?? ?? ?? ?? ?? 45 0F B6 E8 E8 ?? ?? ?? ?? 48 85 C0 75 ?? 48 " @@ -37,9 +44,12 @@ static const auto pattern_MaxPlayerNumsPtr = extern uint64_t GameResourceServicePtr; extern uint64_t FireEventServerSidePtr; extern uint64_t Module_tier0; -extern uint64_t NetworkStateChangedPtr; extern uint64_t Host_SayPtr; extern uint64_t MaxPlayerNumsPtr; extern HashFunction_t FnServerHashFunction; +extern StateChanged_t FnStateChanged; +extern NetworkStateChanged_t FnNetworkStateChanged; + + auto Init() -> bool; }; // namespace Offset diff --git a/csgo2/script_apis.cpp b/csgo2/script_apis.cpp index ca0440c..91e7d09 100644 --- a/csgo2/script_apis.cpp +++ b/csgo2/script_apis.cpp @@ -1,4 +1,16 @@ #include "script_apis.h" +enum class _luaApi_WeaponType { + kOther, + kKnife, + kGun, +}; +struct _luaApi_WeaponInfo { + bool isSuccess; + int Ammo; + int ReserveAmmo; + std::string weaponName; + int weaponType; +}; namespace ScriptApis { // ·µ»ØÊÇ·µ»ØÖµÊýÁ¿,·µ»ØÖµÄÚÈÝÒª×Ô¼ºpushµ½stackÉÏ auto luaApi_ListenToGameEvent(lua_State* luaVm) -> int { @@ -21,7 +33,8 @@ auto luaApi_ListenToGameEvent(lua_State* luaVm) -> int { } // ½«»Øµ÷Ìí¼Óµ½Ó³ÉäÖÐ std::unique_lock lock(ScriptCallBacks::mutex_callbackList); - ScriptCallBacks::callbackList[luaVm][callbackType] = luaL_ref(luaVm, LUA_REGISTRYINDEX); + ScriptCallBacks::callbackList[luaVm][callbackType] = + luaL_ref(luaVm, LUA_REGISTRYINDEX); LOG("luaApi_ListenToGameEvent eventName:%s callback added\n", eventName); @@ -30,7 +43,106 @@ auto luaApi_ListenToGameEvent(lua_State* luaVm) -> int { lua_pop(luaVm, 2); // ÇåÀí¶ÑÕ» return 0; } +auto luaApi_SetPlayerCurrentWeaponAmmo(lua_State* luaVm) -> int { + const auto playerIndex = lua_tointeger(luaVm, 1); + const auto playerAmmoNum = lua_tointeger(luaVm, 2); + const auto playerReserveAmmoNum = lua_tointeger(luaVm, 3); + + CGameEntitySystem* EntitySystem = CGameEntitySystem::GetInstance(); + do { + if (EntitySystem == nullptr || playerIndex == 0) { + break; + } + auto player = EntitySystem->GetBaseEntity(playerIndex); + if (player == nullptr) { + break; + } + if (player->IsBasePlayerController() == false) { + break; + } + auto playerController = reinterpret_cast(player); + const auto weaponServices = playerController->m_hPawn().Get()->m_pWeaponServices(); + if (weaponServices == nullptr) { + break; + } + const auto activeWeapon = weaponServices->m_hActiveWeapon().Get(); + if (activeWeapon == nullptr) { + break; + } + if (playerAmmoNum != -1) { + activeWeapon->m_iClip1(playerAmmoNum); + } + if (playerReserveAmmoNum != -1) { + activeWeapon->m_pReserveAmmo(playerReserveAmmoNum); + } + } while (false); + lua_pop(luaVm, 3); + return 0; +} +auto luaApi_GetPlayerCurrentWeaponInfo(lua_State* luaVm) -> _luaApi_WeaponInfo { + // param: playerIndex:int + const auto playerIndex = lua_tointeger(luaVm, 1); + _luaApi_WeaponInfo info{0}; + + CGameEntitySystem* EntitySystem = CGameEntitySystem::GetInstance(); + do { + if (EntitySystem == nullptr || playerIndex == 0) { + break; + } + auto player = EntitySystem->GetBaseEntity(playerIndex); + if (player == nullptr) { + break; + } + if (player->IsBasePlayerController() == false) { + break; + } + auto playerController = reinterpret_cast(player); + const auto weaponServices = playerController->m_hPawn().Get()->m_pWeaponServices(); + if (weaponServices == nullptr) { + break; + } + const auto activeWeapon = weaponServices->m_hActiveWeapon().Get(); + if (activeWeapon == nullptr) { + break; + } + const auto attributeManager = activeWeapon->m_AttributeManager(); + if (activeWeapon == nullptr) { + break; + } + const auto itemView = attributeManager->m_Item(); + if (itemView == nullptr) { + break; + } + const auto itemStaticData = itemView->GetStaticData(); + if (itemView == nullptr) { + break; + } + const char* checkWeaponName = Offset::InterFaces::ILocalize->FindSafe(itemStaticData->m_pszItemBaseName); + if (checkWeaponName == nullptr || strlen(checkWeaponName) < 1) { + break; + } + info.isSuccess = true; + info.Ammo = activeWeapon->m_iClip1(); + info.ReserveAmmo = activeWeapon->m_pReserveAmmo(); + info.weaponName = itemStaticData->GetSimpleWeaponName(); + info.weaponType = static_cast(itemStaticData->IsKnife(false) ? _luaApi_WeaponType::kKnife : (itemStaticData->IsWeapon() ? _luaApi_WeaponType::kGun : _luaApi_WeaponType::kOther)); + } while (false); + + return info; +} auto initFunciton(lua_State* luaVm) -> void { lua_register(luaVm, "ListenToGameEvent", luaApi_ListenToGameEvent); + lua_register(luaVm, "luaApi_SetPlayerCurrentWeaponAmmo", luaApi_SetPlayerCurrentWeaponAmmo); + //ÎÒ²»Ï²»¶Ëû + luabridge::getGlobalNamespace(luaVm) + .beginClass<_luaApi_WeaponInfo>("WeaponInfo") + .addConstructor() + .addData("isSuccess", &_luaApi_WeaponInfo::isSuccess) + .addData("Ammo", &_luaApi_WeaponInfo::Ammo) + .addData("ReserveAmmo", &_luaApi_WeaponInfo::ReserveAmmo) + .addData("weaponName", &_luaApi_WeaponInfo::weaponName) + .addData("weaponType", &_luaApi_WeaponInfo::weaponType) + .endClass() + .addFunction("luaApi_GetPlayerCurrentWeaponInfo", &luaApi_GetPlayerCurrentWeaponInfo); } }; // namespace ScriptApis diff --git a/csgo2/script_callbacks.cpp b/csgo2/script_callbacks.cpp index fe5ba7e..72864c6 100644 --- a/csgo2/script_callbacks.cpp +++ b/csgo2/script_callbacks.cpp @@ -86,7 +86,7 @@ auto luaCall_onPlayerDisconnect(int player, int slot, const char* pszName, } }); } -auto luaCall_onPlayerDeath(int victim, int killer) -> void { +auto luaCall_onPlayerDeath(int victim, int killer, bool isHeadShot) -> void { ExcuteCallbackInAllLuaVm(_CallbackNames::kOnPlayerDeath, [&](lua_State* luaVm, int refIndex) -> void { lua_rawgeti(luaVm, LUA_REGISTRYINDEX, @@ -94,7 +94,9 @@ auto luaCall_onPlayerDeath(int victim, int killer) -> void { if (lua_isfunction(luaVm, -1)) { lua_pushinteger(luaVm, victim); lua_pushinteger(luaVm, killer); - if (lua_pcall(luaVm, 2, 0, 0) != LUA_OK) { + lua_pushboolean(luaVm, isHeadShot); + + if (lua_pcall(luaVm, 3, 0, 0) != LUA_OK) { LOG("Error calling Lua callback: %s\n", lua_tostring(luaVm, -1)); lua_pop(luaVm, 1); diff --git a/csgo2/script_callbacks.h b/csgo2/script_callbacks.h index e24cfd1..d5f4d22 100644 --- a/csgo2/script_callbacks.h +++ b/csgo2/script_callbacks.h @@ -18,5 +18,5 @@ auto luaCall_onPlayerDisconnect(int player, int slot, const char* pszName, uint64_t xuid, const char* pszNetworkID, const char* pszAddress, bool bFakePlayer) -> void; -auto luaCall_onPlayerDeath(int victim, int killer) -> void; +auto luaCall_onPlayerDeath(int victim, int killer, bool isHeadShot) -> void; } // namespace ScriptCallBacks diff --git a/csgo2/script_engine.cpp b/csgo2/script_engine.cpp index 2231086..eccf79d 100644 --- a/csgo2/script_engine.cpp +++ b/csgo2/script_engine.cpp @@ -42,9 +42,10 @@ auto initLuaScripts() -> void { std::string dirName = dirNames[i]; lua_State* L = luaL_newstate(); - ScriptApis::initFunciton(L); luaL_openlibs(L); + ScriptApis::initFunciton(L); + pluginEnvs[dirName] = L; std::string file = dirPath + "\\main.lua"; diff --git a/csgo2/sdk/public/bitvec.h b/csgo2/sdk/public/bitvec.h new file mode 100644 index 0000000..bdbf1d5 --- /dev/null +++ b/csgo2/sdk/public/bitvec.h @@ -0,0 +1,1397 @@ +//===== Copyright � 1996-2005, Valve Corporation, All rights reserved. ======// +// +// Purpose: +// +//===========================================================================// + +#ifndef BITVEC_H +#define BITVEC_H +#ifdef _WIN32 +#pragma once +#endif + +#include "../sdk.h" +class CBitVecAccessor +{ +public: + CBitVecAccessor(uint32_t *pDWords, int iBit); + + void operator=(int val); + operator uint32_t(); + +private: + uint32_t *m_pDWords; + int m_iBit; +}; + + +//----------------------------------------------------------------------------- +// Support functions +//----------------------------------------------------------------------------- + +#define LOG2_BITS_PER_INT 5 +#define BITS_PER_INT 32 + +#if _WIN32 && !defined(_X360) +#include +#pragma intrinsic(_BitScanForward) +#endif + +inline int FirstBitInWord( unsigned int elem, int offset ) +{ +#if _WIN32 + if ( !elem ) + return -1; +#if _X360 + // this implements CountTrailingZeros() / BitScanForward() + unsigned int mask = elem-1; + unsigned int comp = ~elem; + elem = mask & comp; + return (32 - _CountLeadingZeros(elem)) + offset; +#else + unsigned long out; + _BitScanForward(&out, elem); + return out + offset; +#endif + +#else + static unsigned firstBitLUT[256] = + { + 0,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5,0,1,0,2,0,1,0, + 3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,6,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, + 4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0, + 3,0,1,0,2,0,1,0,7,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, + 5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,6,0,1,0,2,0,1,0, + 3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, + 4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0 + }; + unsigned elemByte; + + elemByte = (elem & 0xFF); + if ( elemByte ) + return offset + firstBitLUT[elemByte]; + + elem >>= 8; + offset += 8; + elemByte = (elem & 0xFF); + if ( elemByte ) + return offset + firstBitLUT[elemByte]; + + elem >>= 8; + offset += 8; + elemByte = (elem & 0xFF); + if ( elemByte ) + return offset + firstBitLUT[elemByte]; + + elem >>= 8; + offset += 8; + elemByte = (elem & 0xFF); + if ( elemByte ) + return offset + firstBitLUT[elemByte]; + + return -1; +#endif +} + +//------------------------------------- + +inline unsigned GetEndMask( int numBits ) +{ + static unsigned bitStringEndMasks[] = + { + 0xffffffff, + 0x00000001, + 0x00000003, + 0x00000007, + 0x0000000f, + 0x0000001f, + 0x0000003f, + 0x0000007f, + 0x000000ff, + 0x000001ff, + 0x000003ff, + 0x000007ff, + 0x00000fff, + 0x00001fff, + 0x00003fff, + 0x00007fff, + 0x0000ffff, + 0x0001ffff, + 0x0003ffff, + 0x0007ffff, + 0x000fffff, + 0x001fffff, + 0x003fffff, + 0x007fffff, + 0x00ffffff, + 0x01ffffff, + 0x03ffffff, + 0x07ffffff, + 0x0fffffff, + 0x1fffffff, + 0x3fffffff, + 0x7fffffff, + }; + + return bitStringEndMasks[numBits % BITS_PER_INT]; +} + + +inline int GetBitForBitnum( int bitNum ) +{ + static int bitsForBitnum[] = + { + ( 1 << 0 ), + ( 1 << 1 ), + ( 1 << 2 ), + ( 1 << 3 ), + ( 1 << 4 ), + ( 1 << 5 ), + ( 1 << 6 ), + ( 1 << 7 ), + ( 1 << 8 ), + ( 1 << 9 ), + ( 1 << 10 ), + ( 1 << 11 ), + ( 1 << 12 ), + ( 1 << 13 ), + ( 1 << 14 ), + ( 1 << 15 ), + ( 1 << 16 ), + ( 1 << 17 ), + ( 1 << 18 ), + ( 1 << 19 ), + ( 1 << 20 ), + ( 1 << 21 ), + ( 1 << 22 ), + ( 1 << 23 ), + ( 1 << 24 ), + ( 1 << 25 ), + ( 1 << 26 ), + ( 1 << 27 ), + ( 1 << 28 ), + ( 1 << 29 ), + ( 1 << 30 ), + ( 1 << 31 ), + }; + + return bitsForBitnum[ (bitNum) & (BITS_PER_INT-1) ]; +} + +inline int GetBitForBitnumByte( int bitNum ) +{ + static int bitsForBitnum[] = + { + ( 1 << 0 ), + ( 1 << 1 ), + ( 1 << 2 ), + ( 1 << 3 ), + ( 1 << 4 ), + ( 1 << 5 ), + ( 1 << 6 ), + ( 1 << 7 ), + }; + + return bitsForBitnum[ bitNum & 7 ]; +} + +inline int CalcNumIntsForBits( int numBits ) { return (numBits + (BITS_PER_INT-1)) / BITS_PER_INT; } + +#ifdef _X360 +#define BitVec_Bit( bitNum ) GetBitForBitnum( bitNum ) +#define BitVec_BitInByte( bitNum ) GetBitForBitnumByte( bitNum ) +#else +#define BitVec_Bit( bitNum ) ( 1 << ( (bitNum) & (BITS_PER_INT-1) ) ) +#define BitVec_BitInByte( bitNum ) ( 1 << ( (bitNum) & 7 ) ) +#endif +#define BitVec_Int( bitNum ) ( (bitNum) >> LOG2_BITS_PER_INT ) + + +//----------------------------------------------------------------------------- +// template CBitVecT +// +// Defines the operations relevant to any bit array. Simply requires a base +// class that implements GetNumBits(), Base(), GetNumDWords() & ValidateOperand() +// +// CVarBitVec and CBitVec are the actual classes generally used +// by clients +// + +template +class CBitVecT : public BASE_OPS +{ +public: + CBitVecT(); + CBitVecT(int numBits); // Must be initialized with the number of bits + + void Init(int val = 0); + + // Access the bits like an array. + CBitVecAccessor operator[](int i); + + // Do NOT override bitwise operators (see note in header) + void And(const CBitVecT &andStr, CBitVecT *out) const; + void Or(const CBitVecT &orStr, CBitVecT *out) const; + void Xor(const CBitVecT &orStr, CBitVecT *out) const; + + void Not(CBitVecT *out) const; + + void CopyTo(CBitVecT *out) const; + void Copy( const CBitVecT &other, int nBits=-1 ); + bool Compare( const CBitVecT &other, int nBits=-1 ) const; + + bool IsAllClear(void) const; // Are all bits zero? + bool IsAllSet(void) const; // Are all bits one? + + uint32_t Get( uint32_t bitNum ) const; + bool IsBitSet( int bitNum ) const; + void Set( int bitNum ); + void Set( int bitNum, bool bNewVal ); + void Clear(int bitNum); + + bool TestAndSet(int bitNum); + + void Set( uint32_t offset, uint32_t mask ); + void Clear( uint32_t offset, uint32_t mask ); + uint32_t Get( uint32_t offset, uint32_t mask ); + + void SetAll(void); // Sets all bits + void ClearAll(void); // Clears all bits + + uint32_t GetDWord(int i) const; + void SetDWord(int i, uint32_t val); + + CBitVecT& operator=(const CBitVecT &other) { other.CopyTo( this ); return *this; } + bool operator==(const CBitVecT &other) { return Compare( other ); } + bool operator!=(const CBitVecT &other) { return !operator==( other ); } + + static void GetOffsetMaskForBit( uint32_t bitNum, uint32_t *pOffset, uint32_t *pMask ) { *pOffset = BitVec_Int( bitNum ); *pMask = BitVec_Bit( bitNum ); } +}; + +//----------------------------------------------------------------------------- +// class CVarBitVecBase +// +// Defines the operations necessary for a variable sized bit array + +class CVarBitVecBase +{ +public: + bool IsFixedSize() const { return false; } + int GetNumBits(void) const { return m_numBits; } + void Resize( int numBits, bool bClearAll = false ); // resizes bit array + + int GetNumDWords() const { return m_numInts; } + uint32_t *Base() { return m_pInt; } + const uint32_t *Base() const { return m_pInt; } + + void Attach( uint32_t *pBits, int numBits ); + bool Detach( uint32_t **ppBits, int *pNumBits ); + + int FindNextSetBit(int iStartBit) const; // returns -1 if no set bit was found + +protected: + CVarBitVecBase(); + CVarBitVecBase(int numBits); + CVarBitVecBase( const CVarBitVecBase &from ); + CVarBitVecBase &operator=( const CVarBitVecBase &from ); + ~CVarBitVecBase(void); + + void ValidateOperand( const CVarBitVecBase &operand ) const { } + + unsigned GetEndMask() const { return ::GetEndMask( GetNumBits() ); } + +private: + + unsigned short m_numBits; // Number of bits in the bitstring + unsigned short m_numInts; // Number of ints to needed to store bitstring + uint32_t m_iBitStringStorage; // If the bit string fits in one int, it goes here + uint32_t * m_pInt; // Array of ints containing the bitstring + + void AllocInts( int numInts ); // Free the allocated bits + void ReallocInts( int numInts ); + void FreeInts( void ); // Free the allocated bits +}; + +//----------------------------------------------------------------------------- +// class CFixedBitVecBase +// +// Defines the operations necessary for a fixed sized bit array. +// + +template struct BitCountToEndMask_t { }; +template <> struct BitCountToEndMask_t< 0> { enum { MASK = 0xffffffff }; }; +template <> struct BitCountToEndMask_t< 1> { enum { MASK = 0x00000001 }; }; +template <> struct BitCountToEndMask_t< 2> { enum { MASK = 0x00000003 }; }; +template <> struct BitCountToEndMask_t< 3> { enum { MASK = 0x00000007 }; }; +template <> struct BitCountToEndMask_t< 4> { enum { MASK = 0x0000000f }; }; +template <> struct BitCountToEndMask_t< 5> { enum { MASK = 0x0000001f }; }; +template <> struct BitCountToEndMask_t< 6> { enum { MASK = 0x0000003f }; }; +template <> struct BitCountToEndMask_t< 7> { enum { MASK = 0x0000007f }; }; +template <> struct BitCountToEndMask_t< 8> { enum { MASK = 0x000000ff }; }; +template <> struct BitCountToEndMask_t< 9> { enum { MASK = 0x000001ff }; }; +template <> struct BitCountToEndMask_t<10> { enum { MASK = 0x000003ff }; }; +template <> struct BitCountToEndMask_t<11> { enum { MASK = 0x000007ff }; }; +template <> struct BitCountToEndMask_t<12> { enum { MASK = 0x00000fff }; }; +template <> struct BitCountToEndMask_t<13> { enum { MASK = 0x00001fff }; }; +template <> struct BitCountToEndMask_t<14> { enum { MASK = 0x00003fff }; }; +template <> struct BitCountToEndMask_t<15> { enum { MASK = 0x00007fff }; }; +template <> struct BitCountToEndMask_t<16> { enum { MASK = 0x0000ffff }; }; +template <> struct BitCountToEndMask_t<17> { enum { MASK = 0x0001ffff }; }; +template <> struct BitCountToEndMask_t<18> { enum { MASK = 0x0003ffff }; }; +template <> struct BitCountToEndMask_t<19> { enum { MASK = 0x0007ffff }; }; +template <> struct BitCountToEndMask_t<20> { enum { MASK = 0x000fffff }; }; +template <> struct BitCountToEndMask_t<21> { enum { MASK = 0x001fffff }; }; +template <> struct BitCountToEndMask_t<22> { enum { MASK = 0x003fffff }; }; +template <> struct BitCountToEndMask_t<23> { enum { MASK = 0x007fffff }; }; +template <> struct BitCountToEndMask_t<24> { enum { MASK = 0x00ffffff }; }; +template <> struct BitCountToEndMask_t<25> { enum { MASK = 0x01ffffff }; }; +template <> struct BitCountToEndMask_t<26> { enum { MASK = 0x03ffffff }; }; +template <> struct BitCountToEndMask_t<27> { enum { MASK = 0x07ffffff }; }; +template <> struct BitCountToEndMask_t<28> { enum { MASK = 0x0fffffff }; }; +template <> struct BitCountToEndMask_t<29> { enum { MASK = 0x1fffffff }; }; +template <> struct BitCountToEndMask_t<30> { enum { MASK = 0x3fffffff }; }; +template <> struct BitCountToEndMask_t<31> { enum { MASK = 0x7fffffff }; }; + +//------------------------------------- + +template +class CFixedBitVecBase +{ +public: + bool IsFixedSize() const { return true; } + int GetNumBits(void) const { return NUM_BITS; } + void Resize( int numBits, bool bClearAll = false ) { Assert(numBits == NUM_BITS); if ( bClearAll ) Plat_FastMemset( m_Ints, 0, NUM_INTS * sizeof(uint32_t) ); }// for syntatic consistency (for when using templates) + + int GetNumDWords() const { return NUM_INTS; } + uint32_t * Base() { return m_Ints; } + const uint32_t * Base() const { return m_Ints; } + + int FindNextSetBit(int iStartBit) const; // returns -1 if no set bit was found + +protected: + CFixedBitVecBase() {} + CFixedBitVecBase(int numBits) { Assert( numBits == NUM_BITS ); } // doesn't make sense, really. Supported to simplify templates & allow easy replacement of variable + + void ValidateOperand( const CFixedBitVecBase &operand ) const { } // no need, compiler does so statically + +public: // for test code + unsigned GetEndMask() const { return static_cast( BitCountToEndMask_t::MASK ); } + +private: + enum + { + NUM_INTS = (NUM_BITS + (BITS_PER_INT-1)) / BITS_PER_INT + }; + + uint32_t m_Ints[(NUM_BITS + (BITS_PER_INT-1)) / BITS_PER_INT]; +}; + +//----------------------------------------------------------------------------- +// +// The actual classes used +// + +// inheritance instead of typedef to allow forward declarations +class CVarBitVec : public CBitVecT +{ +public: + CVarBitVec() + { + } + + CVarBitVec(int numBits) + : CBitVecT(numBits) + { + } +}; + +//----------------------------------------------------------------------------- + +template < int NUM_BITS > +class CBitVec : public CBitVecT< CFixedBitVecBase > +{ +public: + CBitVec() + { + } + + CBitVec(int numBits) + : CBitVecT< CFixedBitVecBase >(numBits) + { + } +}; + + +//----------------------------------------------------------------------------- + +typedef CBitVec<32> CDWordBitVec; + +//----------------------------------------------------------------------------- + +inline CVarBitVecBase::CVarBitVecBase() +{ + Plat_FastMemset( this, 0, sizeof( *this ) ); +} + +//----------------------------------------------------------------------------- + +inline CVarBitVecBase::CVarBitVecBase(int numBits) +{ + m_numBits = numBits; + + // Figure out how many ints are needed + m_numInts = CalcNumIntsForBits( numBits ); + m_pInt = NULL; + AllocInts( m_numInts ); +} + +//----------------------------------------------------------------------------- + +inline CVarBitVecBase::CVarBitVecBase( const CVarBitVecBase &from ) +{ + if ( from.m_numInts ) + { + m_numBits = from.m_numBits; + m_numInts = from.m_numInts; + m_pInt = NULL; + AllocInts( m_numInts ); + memcpy( m_pInt, from.m_pInt, m_numInts * sizeof(int) ); + } + else + memset( this, 0, sizeof( *this ) ); +} + +//----------------------------------------------------------------------------- + +inline CVarBitVecBase &CVarBitVecBase::operator=( const CVarBitVecBase &from ) +{ + Resize( from.GetNumBits() ); + if ( m_pInt ) + memcpy( m_pInt, from.m_pInt, m_numInts * sizeof(int) ); + return (*this); +} + +//----------------------------------------------------------------------------- +// Purpose: Destructor +// Input : +// Output : +//----------------------------------------------------------------------------- + +inline CVarBitVecBase::~CVarBitVecBase(void) +{ + FreeInts(); +} + +//----------------------------------------------------------------------------- + +inline void CVarBitVecBase::Attach( uint32_t *pBits, int numBits ) +{ + FreeInts(); + m_numBits = numBits; + m_numInts = CalcNumIntsForBits( numBits ); + if ( m_numInts > 1 ) + { + m_pInt = pBits; + } + else + { + m_iBitStringStorage = *pBits; + m_pInt = &m_iBitStringStorage; + free( pBits ); + } +} + +//----------------------------------------------------------------------------- + +inline bool CVarBitVecBase::Detach( uint32_t **ppBits, int *pNumBits ) +{ + if ( !m_numBits ) + { + return false; + } + + *pNumBits = m_numBits; + if ( m_numInts > 1 ) + { + *ppBits = m_pInt; + } + else + { + *ppBits = (uint32_t *)malloc( sizeof(uint32_t) ); + **ppBits = m_iBitStringStorage; + free( m_pInt ); + } + + memset( this, 0, sizeof( *this ) ); + return true; +} + +//----------------------------------------------------------------------------- + +template +inline CBitVecT::CBitVecT() +{ + // undef this is ints are not 4 bytes + // generate a compile error if sizeof(int) is not 4 (HACK: can't use the preprocessor so use the compiler) + + // Initialize bitstring by clearing all bits + ClearAll(); +} + +//----------------------------------------------------------------------------- +template +inline CBitVecT::CBitVecT(int numBits) + : BASE_OPS( numBits ) +{ + // undef this is ints are not 4 bytes + // generate a compile error if sizeof(int) is not 4 (HACK: can't use the preprocessor so use the compiler) + + // Initialize bitstring by clearing all bits + ClearAll(); +} + +//----------------------------------------------------------------------------- + +template +inline CBitVecAccessor CBitVecT::operator[](int i) +{ + Assert(i >= 0 && i < this->GetNumBits()); + return CBitVecAccessor(this->Base(), i); +} + + +//----------------------------------------------------------------------------- + +template +inline void CBitVecT::Init( int val ) +{ + if ( this->Base() ) + Plat_FastMemset( this->Base(), ( val ) ? 0xff : 0, this->GetNumDWords() * sizeof(int) ); +} + +//----------------------------------------------------------------------------- + +template +inline uint32_t CBitVecT::Get( uint32_t bitNum ) const +{ + Assert( bitNum < (uint32_t)this->GetNumBits() ); + const uint32_t *pInt = this->Base() + BitVec_Int( bitNum ); + return ( *pInt & BitVec_Bit( bitNum ) ); +} + +//----------------------------------------------------------------------------- + +template +inline bool CBitVecT::IsBitSet( int bitNum ) const +{ + Assert( bitNum >= 0 && bitNum < this->GetNumBits() ); + const uint32_t *pInt = this->Base() + BitVec_Int( bitNum ); + return ( ( *pInt & BitVec_Bit( bitNum ) ) != 0 ); +} + +//----------------------------------------------------------------------------- + +template +inline void CBitVecT::Set( int bitNum ) +{ + Assert( bitNum >= 0 && bitNum < this->GetNumBits() ); + uint32_t *pInt = this->Base() + BitVec_Int( bitNum ); + *pInt |= BitVec_Bit( bitNum ); +} + +//----------------------------------------------------------------------------- + +template +inline bool CBitVecT::TestAndSet(int bitNum) +{ + Assert( bitNum >= 0 && bitNum < this->GetNumBits() ); + uint32_t bitVecBit = BitVec_Bit( bitNum ); + uint32_t *pInt = this->Base() + BitVec_Int( bitNum ); + bool bResult = ( ( *pInt & bitVecBit) != 0 ); + *pInt |= bitVecBit; + return bResult; +} + +//----------------------------------------------------------------------------- + +template +inline void CBitVecT::Clear(int bitNum) +{ + Assert( bitNum >= 0 && bitNum < this->GetNumBits() ); + uint32_t *pInt = this->Base() + BitVec_Int( bitNum ); + *pInt &= ~BitVec_Bit( bitNum ); +} + +//----------------------------------------------------------------------------- + +template +inline void CBitVecT::Set( int bitNum, bool bNewVal ) +{ + uint32_t *pInt = this->Base() + BitVec_Int( bitNum ); + uint32_t bitMask = BitVec_Bit( bitNum ); + if ( bNewVal ) + { + *pInt |= bitMask; + } + else + { + *pInt &= ~bitMask; + } +} + +//----------------------------------------------------------------------------- + +template +inline void CBitVecT::Set( uint32_t offset, uint32_t mask ) +{ + uint32_t *pInt = this->Base() + offset; + *pInt |= mask; +} + +//----------------------------------------------------------------------------- + +template +inline void CBitVecT::Clear( uint32_t offset, uint32_t mask ) +{ + uint32_t *pInt = this->Base() + offset; + *pInt &= ~mask; +} + +//----------------------------------------------------------------------------- + +template +inline uint32_t CBitVecT::Get( uint32_t offset, uint32_t mask ) +{ + uint32_t *pInt = this->Base() + offset; + return ( *pInt & mask ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : +// Output : +//----------------------------------------------------------------------------- +template +inline void CBitVecT::And(const CBitVecT &addStr, CBitVecT *out) const +{ + ValidateOperand( addStr ); + ValidateOperand( *out ); + + uint32_t * pDest = out->Base(); + const uint32_t *pOperand1 = this->Base(); + const uint32_t *pOperand2 = addStr.Base(); + + for (int i = this->GetNumDWords() - 1; i >= 0 ; --i) + { + pDest[i] = pOperand1[i] & pOperand2[i]; + } +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : +// Output : +//----------------------------------------------------------------------------- +template +inline void CBitVecT::Or(const CBitVecT &orStr, CBitVecT *out) const +{ + ValidateOperand( orStr ); + ValidateOperand( *out ); + + uint32_t * pDest = out->Base(); + const uint32_t *pOperand1 = this->Base(); + const uint32_t *pOperand2 = orStr.Base(); + + for (int i = this->GetNumDWords() - 1; i >= 0; --i) + { + pDest[i] = pOperand1[i] | pOperand2[i]; + } +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : +// Output : +//----------------------------------------------------------------------------- +template +inline void CBitVecT::Xor(const CBitVecT &xorStr, CBitVecT *out) const +{ + uint32_t * pDest = out->Base(); + const uint32_t *pOperand1 = this->Base(); + const uint32_t *pOperand2 = xorStr.Base(); + + for (int i = this->GetNumDWords() - 1; i >= 0; --i) + { + pDest[i] = pOperand1[i] ^ pOperand2[i]; + } +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : +// Output : +//----------------------------------------------------------------------------- +template +inline void CBitVecT::Not(CBitVecT *out) const +{ + ValidateOperand( *out ); + + uint32_t * pDest = out->Base(); + const uint32_t *pOperand = this->Base(); + + for (int i = this->GetNumDWords() - 1; i >= 0; --i) + { + pDest[i] = ~(pOperand[i]); + } +} + +//----------------------------------------------------------------------------- +// Purpose: Copy a bit string +// Input : +// Output : +//----------------------------------------------------------------------------- +template +inline void CBitVecT::CopyTo(CBitVecT *out) const +{ + out->Resize( this->GetNumBits() ); + + ValidateOperand( *out ); + Assert( out != this ); + + memcpy( out->Base(), this->Base(), this->GetNumDWords() * sizeof( int ) ); +} + +//----------------------------------------------------------------------------- +// Purpose: Are all bits zero? +// Input : +// Output : +//----------------------------------------------------------------------------- +template +inline bool CBitVecT::IsAllClear(void) const +{ + // Number of available bits may be more than the number + // actually used, so make sure to mask out unused bits + // before testing for zero + (const_cast(this))->Base()[this->GetNumDWords()-1] &= CBitVecT::GetEndMask(); // external semantics of const retained + + for (int i = this->GetNumDWords() - 1; i >= 0; --i) + { + if ( this->Base()[i] !=0 ) + { + return false; + } + } + return true; +} + +//----------------------------------------------------------------------------- +// Purpose: Are all bits set? +// Input : +// Output : +//----------------------------------------------------------------------------- +template +inline bool CBitVecT::IsAllSet(void) const +{ + // Number of available bits may be more than the number + // actually used, so make sure to mask out unused bits + // before testing for set bits + (const_cast(this))->Base()[this->GetNumDWords()-1] |= ~CBitVecT::GetEndMask(); // external semantics of const retained + + for (int i = this->GetNumDWords() - 1; i >= 0; --i) + { + if ( this->Base()[i] != ~0 ) + { + return false; + } + } + return true; +} + +//----------------------------------------------------------------------------- +// Purpose: Sets all bits +// Input : +// Output : +//----------------------------------------------------------------------------- +template +inline void CBitVecT::SetAll(void) +{ + if ( this->Base() ) + Plat_FastMemset( this->Base(), 0xff, this->GetNumDWords() * sizeof(int) ); +} + +//----------------------------------------------------------------------------- +// Purpose: Clears all bits +// Input : +// Output : +//----------------------------------------------------------------------------- +template +inline void CBitVecT::ClearAll(void) +{ + if ( this->Base() ) + Plat_FastMemset( this->Base(), 0, this->GetNumDWords() * sizeof(int) ); +} + +//----------------------------------------------------------------------------- +template +inline void CBitVecT::Copy( const CBitVecT &other, int nBits ) +{ + if ( nBits == - 1 ) + { + nBits = other.GetNumBits(); + } + + this->Resize( nBits ); + + ValidateOperand( other ); + Assert( &other != this ); + + memcpy( this->Base(), other.Base(), this->GetNumDWords() * sizeof( uint32_t ) ); +} + +//----------------------------------------------------------------------------- +template +inline bool CBitVecT::Compare( const CBitVecT &other, int nBits ) const +{ + if ( nBits == - 1 ) + { + if ( other.GetNumBits() != this->GetNumBits() ) + { + return false; + } + + nBits = other.GetNumBits(); + } + + if ( nBits > other.GetNumBits() || nBits > this->GetNumBits() ) + { + return false; + } + + (const_cast(this))->Base()[this->GetNumDWords()-1] &= CBitVecT::GetEndMask(); // external semantics of const retained + (const_cast(&other))->Base()[this->GetNumDWords()-1] &= other.CBitVecT::GetEndMask(); // external semantics of const retained + + int nBytes = PAD_NUMBER( nBits, 8 ) >> 3; + + return ( memcmp( this->Base(), other.Base(), nBytes ) == 0 ); +} + +//----------------------------------------------------------------------------- +template +inline uint32_t CBitVecT::GetDWord(int i) const +{ + Assert(i >= 0 && i < this->GetNumDWords()); + return this->Base()[i]; +} + +//----------------------------------------------------------------------------- +template +inline void CBitVecT::SetDWord(int i, uint32_t val) +{ + Assert(i >= 0 && i < this->GetNumDWords()); + this->Base()[i] = val; +} + +//----------------------------------------------------------------------------- + +inline unsigned GetStartBitMask( int startBit ) +{ + static unsigned int g_StartMask[32] = + { + 0xffffffff, + 0xfffffffe, + 0xfffffffc, + 0xfffffff8, + 0xfffffff0, + 0xffffffe0, + 0xffffffc0, + 0xffffff80, + 0xffffff00, + 0xfffffe00, + 0xfffffc00, + 0xfffff800, + 0xfffff000, + 0xffffe000, + 0xffffc000, + 0xffff8000, + 0xffff0000, + 0xfffe0000, + 0xfffc0000, + 0xfff80000, + 0xfff00000, + 0xffe00000, + 0xffc00000, + 0xff800000, + 0xff000000, + 0xfe000000, + 0xfc000000, + 0xf8000000, + 0xf0000000, + 0xe0000000, + 0xc0000000, + 0x80000000, + }; + + return g_StartMask[ startBit & 31 ]; +} + +inline int CVarBitVecBase::FindNextSetBit( int startBit ) const +{ + if ( startBit < GetNumBits() ) + { + int wordIndex = BitVec_Int(startBit); + unsigned int startMask = GetStartBitMask( startBit ); + int lastWord = GetNumDWords()-1; + + // handle non dword lengths + if ( (GetNumBits() % BITS_PER_INT) != 0 ) + { + unsigned int elem = Base()[wordIndex]; + elem &= startMask; + if ( wordIndex == lastWord) + { + elem &= (GetEndMask()); + // there's a bit remaining in this word + if ( elem ) + return FirstBitInWord(elem, wordIndex << 5); + } + else + { + // there's a bit remaining in this word + if ( elem ) + return FirstBitInWord(elem, wordIndex << 5); + + // iterate the words + for ( int i = wordIndex+1; i < lastWord; i++ ) + { + elem = Base()[i]; + if ( elem ) + return FirstBitInWord(elem, i << 5); + } + elem = Base()[lastWord] & GetEndMask(); + if ( elem ) + return FirstBitInWord(elem, lastWord << 5); + } + } + else + { + const uint32_t * RESTRICT pCurElem = Base() + wordIndex; + unsigned int elem = *pCurElem; + elem &= startMask; + do + { + if ( elem ) + return FirstBitInWord(elem, wordIndex << 5); + ++pCurElem; + elem = *pCurElem; + ++wordIndex; + } while( wordIndex <= lastWord ); + } + + } + + return -1; +} + +template +inline int CFixedBitVecBase::FindNextSetBit( int startBit ) const +{ + if ( startBit < NUM_BITS ) + { + int wordIndex = BitVec_Int(startBit); + unsigned int startMask = GetStartBitMask( startBit ); + + // handle non dword lengths + if ( (NUM_BITS % BITS_PER_INT) != 0 ) + { + unsigned int elem = Base()[wordIndex]; + elem &= startMask; + if ( wordIndex == NUM_INTS-1) + { + elem &= (GetEndMask()); + // there's a bit remaining in this word + if ( elem ) + return FirstBitInWord(elem, wordIndex << 5); + } + else + { + // there's a bit remaining in this word + if ( elem ) + return FirstBitInWord(elem, wordIndex << 5); + + // iterate the words + for ( int i = wordIndex+1; i < NUM_INTS-1; i++ ) + { + elem = Base()[i]; + if ( elem ) + return FirstBitInWord(elem, i << 5); + } + elem = Base()[NUM_INTS-1] & GetEndMask(); + if ( elem ) + return FirstBitInWord(elem, (NUM_INTS-1) << 5); + } + } + else + { + const uint32_t * RESTRICT pCurElem = Base() + wordIndex; + unsigned int elem = *pCurElem; + elem &= startMask; + do + { + if ( elem ) + return FirstBitInWord(elem, wordIndex << 5); + ++pCurElem; + elem = *pCurElem; + ++wordIndex; + } while( wordIndex <= NUM_INTS-1); + } + + } + + return -1; +} + +//----------------------------------------------------------------------------- +// Unrolled loops for some common sizes + +template<> +FORCEINLINE_TEMPLATE void CBitVecT< CFixedBitVecBase<256> >::And(const CBitVecT &addStr, CBitVecT *out) const +{ + uint32_t * pDest = out->Base(); + const uint32_t *pOperand1 = Base(); + const uint32_t *pOperand2 = addStr.Base(); + + pDest[0] = pOperand1[0] & pOperand2[0]; + pDest[1] = pOperand1[1] & pOperand2[1]; + pDest[2] = pOperand1[2] & pOperand2[2]; + pDest[3] = pOperand1[3] & pOperand2[3]; + pDest[4] = pOperand1[4] & pOperand2[4]; + pDest[5] = pOperand1[5] & pOperand2[5]; + pDest[6] = pOperand1[6] & pOperand2[6]; + pDest[7] = pOperand1[7] & pOperand2[7]; +} + +template<> +FORCEINLINE_TEMPLATE bool CBitVecT< CFixedBitVecBase<256> >::IsAllClear(void) const +{ + const uint32_t *pInts = Base(); + return ( pInts[0] == 0 && pInts[1] == 0 && pInts[2] == 0 && pInts[3] == 0 && pInts[4] == 0 && pInts[5] == 0 && pInts[6] == 0 && pInts[7] == 0 ); +} + +template<> +FORCEINLINE_TEMPLATE void CBitVecT< CFixedBitVecBase<256> >::CopyTo(CBitVecT *out) const +{ + uint32_t * pDest = out->Base(); + const uint32_t *pInts = Base(); + + pDest[0] = pInts[0]; + pDest[1] = pInts[1]; + pDest[2] = pInts[2]; + pDest[3] = pInts[3]; + pDest[4] = pInts[4]; + pDest[5] = pInts[5]; + pDest[6] = pInts[6]; + pDest[7] = pInts[7]; +} + +template<> +FORCEINLINE_TEMPLATE void CBitVecT< CFixedBitVecBase<128> >::And(const CBitVecT &addStr, CBitVecT *out) const +{ + uint32_t * pDest = out->Base(); + const uint32_t *pOperand1 = Base(); + const uint32_t *pOperand2 = addStr.Base(); + + pDest[0] = pOperand1[0] & pOperand2[0]; + pDest[1] = pOperand1[1] & pOperand2[1]; + pDest[2] = pOperand1[2] & pOperand2[2]; + pDest[3] = pOperand1[3] & pOperand2[3]; +} + +template<> +FORCEINLINE_TEMPLATE bool CBitVecT< CFixedBitVecBase<128> >::IsAllClear(void) const +{ + const uint32_t *pInts = Base(); + return ( pInts[0] == 0 && pInts[1] == 0 && pInts[2] == 0 && pInts[3] == 0 ); +} + +template<> +FORCEINLINE_TEMPLATE void CBitVecT< CFixedBitVecBase<128> >::CopyTo(CBitVecT *out) const +{ + uint32_t * pDest = out->Base(); + const uint32_t *pInts = Base(); + + pDest[0] = pInts[0]; + pDest[1] = pInts[1]; + pDest[2] = pInts[2]; + pDest[3] = pInts[3]; +} + +template<> +inline void CBitVecT< CFixedBitVecBase<96> >::And(const CBitVecT &addStr, CBitVecT *out) const +{ + uint32_t * pDest = out->Base(); + const uint32_t *pOperand1 = Base(); + const uint32_t *pOperand2 = addStr.Base(); + + pDest[0] = pOperand1[0] & pOperand2[0]; + pDest[1] = pOperand1[1] & pOperand2[1]; + pDest[2] = pOperand1[2] & pOperand2[2]; +} + +template<> +inline bool CBitVecT< CFixedBitVecBase<96> >::IsAllClear(void) const +{ + const uint32_t *pInts = Base(); + return ( pInts[0] == 0 && pInts[1] == 0 && pInts[2] == 0 ); +} + +template<> +inline void CBitVecT< CFixedBitVecBase<96> >::CopyTo(CBitVecT *out) const +{ + uint32_t * pDest = out->Base(); + const uint32_t *pInts = Base(); + + pDest[0] = pInts[0]; + pDest[1] = pInts[1]; + pDest[2] = pInts[2]; +} + +template<> +inline void CBitVecT< CFixedBitVecBase<64> >::And(const CBitVecT &addStr, CBitVecT *out) const +{ + uint32_t * pDest = out->Base(); + const uint32_t *pOperand1 = Base(); + const uint32_t *pOperand2 = addStr.Base(); + + pDest[0] = pOperand1[0] & pOperand2[0]; + pDest[1] = pOperand1[1] & pOperand2[1]; +} + +template<> +inline bool CBitVecT< CFixedBitVecBase<64> >::IsAllClear(void) const +{ + const uint32_t *pInts = Base(); + return ( pInts[0] == 0 && pInts[1] == 0 ); +} + +template<> +inline void CBitVecT< CFixedBitVecBase<64> >::CopyTo(CBitVecT *out) const +{ + uint32_t * pDest = out->Base(); + const uint32_t *pInts = Base(); + + pDest[0] = pInts[0]; + pDest[1] = pInts[1]; +} + +template<> +inline void CBitVecT< CFixedBitVecBase<32> >::And(const CBitVecT &addStr, CBitVecT *out) const +{ + uint32_t * pDest = out->Base(); + const uint32_t *pOperand1 = Base(); + const uint32_t *pOperand2 = addStr.Base(); + + pDest[0] = pOperand1[0] & pOperand2[0]; +} + +template<> +inline bool CBitVecT< CFixedBitVecBase<32> >::IsAllClear(void) const +{ + const uint32_t *pInts = Base(); + + return ( pInts[0] == 0 ); +} + +template<> +inline void CBitVecT< CFixedBitVecBase<32> >::CopyTo(CBitVecT *out) const +{ + uint32_t * pDest = out->Base(); + const uint32_t *pInts = Base(); + + pDest[0] = pInts[0]; +} + +//----------------------------------------------------------------------------- + +template <> +inline uint32_t CBitVecT< CFixedBitVecBase<32> >::Get( uint32_t bitNum ) const +{ + return ( *Base() & BitVec_Bit( bitNum ) ); +} + +//----------------------------------------------------------------------------- + +template <> +inline bool CBitVecT< CFixedBitVecBase<32> >::IsBitSet( int bitNum ) const +{ + return ( ( *Base() & BitVec_Bit( bitNum ) ) != 0 ); +} + +//----------------------------------------------------------------------------- + +template <> +inline void CBitVecT< CFixedBitVecBase<32> >::Set( int bitNum ) +{ + *Base() |= BitVec_Bit( bitNum ); +} + +//----------------------------------------------------------------------------- + +template <> +inline void CBitVecT< CFixedBitVecBase<32> >::Clear(int bitNum) +{ + *Base() &= ~BitVec_Bit( bitNum ); +} + +//----------------------------------------------------------------------------- + +template <> +inline void CBitVecT< CFixedBitVecBase<32> >::Set( int bitNum, bool bNewVal ) +{ + uint32_t bitMask = BitVec_Bit( bitNum ); + if ( bNewVal ) + { + *Base() |= bitMask; + } + else + { + *Base() &= ~bitMask; + } +} + +//----------------------------------------------------------------------------- +// Purpose: Resizes the bit string to a new number of bits +// Input : resizeNumBits - +//----------------------------------------------------------------------------- +inline void CVarBitVecBase::Resize( int resizeNumBits, bool bClearAll ) +{ + int newIntCount = CalcNumIntsForBits( resizeNumBits ); + if ( newIntCount != GetNumDWords() ) + { + if ( Base() ) + { + ReallocInts( newIntCount ); + if ( !bClearAll && resizeNumBits >= GetNumBits() ) + { + Base()[GetNumDWords() - 1] &= GetEndMask(); + Plat_FastMemset( Base() + GetNumDWords(), 0, (newIntCount - GetNumDWords()) * sizeof(int) ); + } + } + else + { + // Figure out how many ints are needed + AllocInts( newIntCount ); + // Initialize bitstring by clearing all bits + bClearAll = true; + } + + m_numInts = newIntCount; + } + else if ( !bClearAll && resizeNumBits >= GetNumBits() && Base() ) + { + Base()[GetNumDWords() - 1] &= GetEndMask(); + } + + if ( bClearAll && Base() ) + { + Plat_FastMemset( Base(), 0, newIntCount * sizeof(int) ); + } + + // store the new size and end mask + m_numBits = resizeNumBits; +} + +//----------------------------------------------------------------------------- +// Purpose: Allocate the storage for the ints +// Input : numInts - +//----------------------------------------------------------------------------- +inline void CVarBitVecBase::AllocInts( int numInts ) +{ + + if ( numInts == 0 ) + return; + + if ( numInts == 1 ) + { + m_pInt = &m_iBitStringStorage; + return; + } + + m_pInt = (uint32_t *)malloc( numInts * sizeof(int) ); +} + + +//----------------------------------------------------------------------------- +// Purpose: Reallocate the storage for the ints +// Input : numInts - +//----------------------------------------------------------------------------- +inline void CVarBitVecBase::ReallocInts( int numInts ) +{ + if ( numInts == 0) + { + FreeInts(); + return; + } + + if ( m_pInt == &m_iBitStringStorage ) + { + if ( numInts != 1 ) + { + m_pInt = ((uint32_t *)malloc( numInts * sizeof(int) )); + *m_pInt = m_iBitStringStorage; + } + + return; + } + + if ( numInts == 1 ) + { + m_iBitStringStorage = *m_pInt; + free( m_pInt ); + m_pInt = &m_iBitStringStorage; + return; + } + + m_pInt = (uint32_t *)realloc( m_pInt, numInts * sizeof(int) ); +} + + +//----------------------------------------------------------------------------- +// Purpose: Free storage allocated with AllocInts +//----------------------------------------------------------------------------- +inline void CVarBitVecBase::FreeInts( void ) +{ + if ( m_numInts > 1 ) + { + free( m_pInt ); + } + m_pInt = NULL; +} + +// ------------------------------------------------------------------------ // +// CBitVecAccessor inlines. +// ------------------------------------------------------------------------ // + +inline CBitVecAccessor::CBitVecAccessor(uint32_t *pDWords, int iBit) +{ + m_pDWords = pDWords; + m_iBit = iBit; +} + + +inline void CBitVecAccessor::operator=(int val) +{ + if(val) + m_pDWords[m_iBit >> 5] |= (1 << (m_iBit & 31)); + else + m_pDWords[m_iBit >> 5] &= ~(unsigned long)(1 << (m_iBit & 31)); +} + +inline CBitVecAccessor::operator uint32_t() +{ + return m_pDWords[m_iBit >> 5] & (1 << (m_iBit & 31)); +} + + +//============================================================================= + +#endif // BITVEC_H diff --git a/csgo2/sdk/public/eiface.h b/csgo2/sdk/public/eiface.h index 7ff2882..a5dd3d3 100644 --- a/csgo2/sdk/public/eiface.h +++ b/csgo2/sdk/public/eiface.h @@ -4,7 +4,10 @@ #include "../tier1/bufferstring.h" #include "../convar/convar.hpp" #include "../protobuf-2.6.1/src/google/protobuf/message.h" +#include "string_t.h" struct vis_info_t; +struct string_t; + class IHLTVServer; class IHLTVDirector; class CSteamID; @@ -17,7 +20,111 @@ class CPlayerBitVec; class edict_t; class CGamestatsData; class KeyValues; -class CGlobalVars; +enum GlobalVarsUsageWarning_t +{ + GV_RENDERTIME_CALLED_DURING_SIMULATION, + GV_CURTIME_CALLED_DURING_RENDERING +}; +enum MapLoadType_t +{ + MapLoad_NewGame = 0, + MapLoad_LoadGame, + MapLoad_Transition, + MapLoad_Background, +}; +typedef void (*FnGlobalVarsWarningFunc)(GlobalVarsUsageWarning_t); + +//----------------------------------------------------------------------------- +// Purpose: Global variables used by shared code +//----------------------------------------------------------------------------- +class CGlobalVarsBase +{ +public: + + CGlobalVarsBase(); + +public: + // Absolute time (per frame still - Use Plat_FloatTime() for a high precision real time + // perf clock, but not that it doesn't obey host_timescale/host_framerate) + float realtime; + // Absolute frame counter - continues to increase even if game is paused + int framecount; + + // Non-paused frametime + float absoluteframetime; + float absoluteframestarttimestddev; + + int maxClients; + + // zer0k: Command queue related + int unknown1; + int unknown2; + + FnGlobalVarsWarningFunc m_pfnWarningFunc; + + // Time spent on last server or client frame (has nothing to do with think intervals) + float frametime; + + // Current time + // + // On the client, this (along with tickcount) takes a different meaning based on what + // piece of code you're in: + // + // - While receiving network packets (like in PreDataUpdate/PostDataUpdate and proxies), + // this is set to the SERVER TICKCOUNT for that packet. There is no interval between + // the server ticks. + // [server_current_Tick * tick_interval] + // + // - While rendering, this is the exact client clock + // [client_current_tick * tick_interval + interpolation_amount] + // + // - During prediction, this is based on the client's current tick: + // [client_current_tick * tick_interval] + float curtime; + float rendertime; + + // zer0k: Command queue + interpolation related + float unknown3; + float unknown4; + + bool m_bInSimulation; + bool m_bEnableAssertions; + + // Simulation ticks - does not increase when game is paused + int tickcount; + // Simulation tick interval + float interval_per_tick; +}; + +inline CGlobalVarsBase::CGlobalVarsBase() +{ +} + +class CGlobalVars : public CGlobalVarsBase +{ +public: + + CGlobalVars(); + +public: + + // Current map + string_t mapname; + string_t startspot; + MapLoadType_t eLoadType; // How the current map was loaded + bool mp_teamplay; + + // current maxentities + int maxEntities; + + int serverCount; +}; + +inline CGlobalVars::CGlobalVars() : + CGlobalVarsBase() +{ + serverCount = 0; +} class CSharedEdictChangeInfo; class IAchievementMgr; class CCommandContext; diff --git a/csgo2/sdk/public/iserver.h b/csgo2/sdk/public/iserver.h new file mode 100644 index 0000000..f64bdeb --- /dev/null +++ b/csgo2/sdk/public/iserver.h @@ -0,0 +1,133 @@ +#pragma once +#include "../sdk.h" +class GameSessionConfiguration_t { }; +class IGameSpawnGroupMgr; +struct EventServerAdvanceTick_t; +struct EventServerPollNetworking_t; +struct EventServerProcessNetworking_t; +struct EventServerSimulate_t; +struct EventServerPostSimulate_t; +struct server_state_t; +class IPrerequisite; +class CServerChangelevelState; +class ISource2WorldSession; +class INetworkGameClient; +class GameSessionConfiguration_t; +typedef int HGameResourceManifest; +struct SpawnGroupDesc_t; +struct EngineLoopState_t; +struct EventMapRegistrationType_t; +class ILoopModeFactory; +struct ActiveLoop_t; +struct EventClientOutput_t; +class ISwitchLoopModeStatusNotify; +class IAddonListChangeNotify; + +enum ESpawnGroupUnloadOption +{ + +}; + +class IConnectionlessPacketHandler +{ +public: + virtual ~IConnectionlessPacketHandler(void) {}; + + virtual bool ProcessConnectionlessPacket(const void* addr, void* bf) = 0; // process a connectionless packet +}; + +class INetworkGameServer : public IConnectionlessPacketHandler +{ +public: + virtual void Init(const GameSessionConfiguration_t&, const char*) = 0; + virtual void SetGameSpawnGroupMgr(IGameSpawnGroupMgr*) = 0; + virtual void SetGameSessionManifest(HGameResourceManifest*) = 0; + virtual void RegisterLoadingSpawnGroups(void*) = 0; + virtual void Shutdown(void) = 0; + virtual void AddRef(void) = 0; + virtual void Release(void) = 0; + virtual CGlobalVars* GetGlobals(void) = 0; + virtual bool IsActive(void) const = 0; + virtual void SetServerTick(int tick) = 0; + virtual int GetServerTick(void) const = 0; // returns game world tick + virtual void SetFinalSimulationTickThisFrame(int) = 0; + virtual int GetMaxClients(void) const = 0; // returns current client limit + virtual float GetTickInterval(void) const = 0; // tick interval in seconds + virtual void ServerAdvanceTick(const EventServerAdvanceTick_t&) = 0; + virtual void ServerPollNetworking(const EventServerPollNetworking_t&) = 0; + virtual void ServerProcessNetworking(const EventServerProcessNetworking_t&) = 0; + virtual void ServerSimulate(const EventServerSimulate_t&) = 0; + virtual void ServerPostSimulate(const EventServerPostSimulate_t&) = 0; + virtual void LoadSpawnGroup(const SpawnGroupDesc_t&) = 0; + virtual void AsyncUnloadSpawnGroup(unsigned int, ESpawnGroupUnloadOption) = 0; + virtual void PrintSpawnGroupStatus(void) const = 0; + virtual float GetTimescale(void) const = 0; // returns the game time scale (multiplied in conjunction with host_timescale) + virtual bool IsSaveRestoreAllowed(void) const = 0; + virtual void SetMapName(const char* pszNewName) = 0; + virtual const char* GetMapName(void) const = 0; // current map name (BSP) + virtual const char* GetAddonName(void) const = 0; + virtual bool IsBackgroundMap(void) const = 0; + virtual float GetTime(void) const = 0; // returns game world time + virtual int GetMapVersion(void) const = 0; + virtual void ActivateServer(void) = 0; + virtual void PrepareForAssetLoad(void) = 0; + virtual int GetServerNetworkAddress(void) = 0; + virtual SpawnGroupHandle_t FindSpawnGroupByName(const char* pszName) = 0; + virtual void MakeSpawnGroupActive(SpawnGroupHandle_t) = 0; + virtual void SynchronouslySpawnGroup(SpawnGroupHandle_t) = 0; + virtual void SetServerState(server_state_t) = 0; + virtual void SpawnServer(const char*) = 0; + virtual void GetSpawnGroupLoadingStatus(SpawnGroupHandle_t) = 0; + virtual void SetSpawnGroupDescription(SpawnGroupHandle_t, const char*) = 0; + virtual void* StartChangeLevel(const char*, const char* pszLandmark, void*) = 0; + virtual void FinishChangeLevel(CServerChangelevelState*) = 0; + virtual bool IsChangelevelPending(void) const = 0; + virtual void GetAllLoadingSpawnGroups(void* pOut) = 0; + virtual void PreserveSteamID(void) = 0; + virtual void OnKickById(const CCommandContext& context, const CCommand& args) = 0; + virtual void OnKickByName(const CCommandContext& context, const CCommand& args) = 0; +}; + +class IEngineService : public IAppSystem +{ +public: + virtual void* GetServiceDependencies(void) = 0; + virtual const char* GetName(void) const = 0; + virtual bool ShouldActivate(const char*) = 0; + virtual void OnLoopActivate(const EngineLoopState_t& loopState, /*CEventDispatcher*/ void*) = 0; + virtual void OnLoopDeactivate(const EngineLoopState_t& loopState, /*CEventDispatcher*/ void*) = 0; + virtual bool IsActive(void) const = 0; + virtual void SetActive(bool) = 0; + virtual void SetName(const char* pszName) = 0; + virtual void RegisterEventMap( /*CEventDispatcher*/ void*, EventMapRegistrationType_t) = 0; + virtual uint16_t GetServiceIndex(void) = 0; + virtual void SetServiceIndex(uint16_t index) = 0; +}; + +class INetworkServerService : public IEngineService +{ +public: + virtual ~INetworkServerService() {} + virtual INetworkGameServer * GetIGameServer(void) = 0; + virtual bool IsActiveInGame(void) const = 0; + virtual bool IsMultiplayer(void) const = 0; + virtual void StartupServer(const GameSessionConfiguration_t& config, ISource2WorldSession* pWorldSession, const char*) = 0; + virtual void SetGameSpawnGroupMgr(IGameSpawnGroupMgr* pMgr) = 0; + virtual void AddServerPrerequisites(const GameSessionConfiguration_t&, const char*, void*, bool) = 0; + virtual void SetServerSocket(int) = 0; + virtual bool IsServerRunning(void) const = 0; + virtual void DisconnectGameNow( /*ENetworkDisconnectionReason*/ int) = 0; + virtual void PrintSpawnGroupStatus(void) const = 0; + virtual void SetFinalSimulationTickThisFrame(int) = 0; + virtual void* GetGameServer(void) = 0; + virtual int GetTickInterval(void) const = 0; + virtual void ProcessSocket(void) = 0; + virtual int GetServerNetworkAddress(void) = 0; + virtual bool GameLoadFailed(void) const = 0; + virtual void SetGameLoadFailed(bool bFailed) = 0; + virtual void SetGameLoadStarted(void) = 0; + virtual void StartChangeLevel(void) = 0; + virtual void PreserveSteamID(void) = 0; + virtual unsigned long GetServerSerializersCRC(void) = 0; + virtual void* GetServerSerializersMsg(void) = 0; +}; diff --git a/csgo2/sdk/public/mathlib.h b/csgo2/sdk/public/mathlib.h new file mode 100644 index 0000000..115f46f --- /dev/null +++ b/csgo2/sdk/public/mathlib.h @@ -0,0 +1,12 @@ +#pragma once +#include "../sdk.h" +FORCEINLINE unsigned int SmallestPowerOfTwoGreaterOrEqual(unsigned int x) +{ + x -= 1; + x |= x >> 1; + x |= x >> 2; + x |= x >> 4; + x |= x >> 8; + x |= x >> 16; + return x + 1; +} diff --git a/csgo2/sdk/public/string_t.h b/csgo2/sdk/public/string_t.h new file mode 100644 index 0000000..12490d8 --- /dev/null +++ b/csgo2/sdk/public/string_t.h @@ -0,0 +1,114 @@ +//========= Copyright ?1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: Defines the more complete set of operations on the string_t defined +// These should be used instead of direct manipulation to allow more +// flexibility in future ports or optimization. +// +// $NoKeywords: $ +//=============================================================================// + +#include +#ifndef STRING_T_H +#define STRING_T_H + +#if defined( _WIN32 ) +#pragma once +#endif + +#ifndef NO_STRING_T + +#ifdef WEAK_STRING_T + +typedef int string_t; + +//----------------------------------------------------------------------------- +// Purpose: The correct way to specify the NULL string as a constant. +//----------------------------------------------------------------------------- + +#define NULL_STRING 0 + +//----------------------------------------------------------------------------- +// Purpose: Given a string_t, make a C string. By convention the result string +// pointer should be considered transient and should not be stored. +//----------------------------------------------------------------------------- + +#define STRING( offset ) ( ( offset ) ? reinterpret_cast( offset ) : "" ) + +//----------------------------------------------------------------------------- +// Purpose: Given a C string, obtain a string_t +//----------------------------------------------------------------------------- + +#define MAKE_STRING( str ) ( ( *str != 0 ) ? reinterpret_cast( str ) : 0 ) + +//----------------------------------------------------------------------------- + +#define IDENT_STRINGS( s1, s2 ) ( *((void **)&(s1)) == *((void **)&(s2)) ) + +//----------------------------------------------------------------------------- + +#else // Strong string_t + +//----------------------------------------------------------------------------- + +struct string_t +{ +public: + bool operator!() const { return ( pszValue == NULL ); } + bool operator==( const string_t &rhs ) const { return ( pszValue == rhs.pszValue ); } + bool operator!=( const string_t &rhs ) const { return ( pszValue != rhs.pszValue ); } + bool operator<( const string_t &rhs ) const { return ((void *)pszValue < (void *)rhs.pszValue ); } + + const char *ToCStr() const { return ( pszValue ) ? pszValue : ""; } + +protected: + const char *pszValue; +}; + +//----------------------------------------------------------------------------- + +struct castable_string_t : public string_t // string_t is used in unions, hence, no constructor allowed +{ + castable_string_t() { pszValue = NULL; } + castable_string_t( const char *pszFrom ) { pszValue = (pszFrom && *pszFrom) ? pszFrom : 0; } +}; + +//----------------------------------------------------------------------------- +// Purpose: The correct way to specify the NULL string as a constant. +//----------------------------------------------------------------------------- + +#define NULL_STRING castable_string_t() + +//----------------------------------------------------------------------------- +// Purpose: Given a string_t, make a C string. By convention the result string +// pointer should be considered transient and should not be stored. +//----------------------------------------------------------------------------- + +#define STRING( string_t_obj ) (string_t_obj).ToCStr() + +//----------------------------------------------------------------------------- +// Purpose: Given a C string, obtain a string_t +//----------------------------------------------------------------------------- + +#define MAKE_STRING( c_str ) castable_string_t( c_str ) + +//----------------------------------------------------------------------------- + +#define IDENT_STRINGS( s1, s2 ) ( *((void **)&(s1)) == *((void **)&(s2)) ) + +//----------------------------------------------------------------------------- + +#endif + +#else // NO_STRING_T + +typedef const char *string_t; +#define NULL_STRING 0 +#define STRING( c_str ) ( c_str ) +#define MAKE_STRING( c_str ) ( c_str ) +#define IDENT_STRINGS( s1, s2 ) ( *((void **)&(s1)) == *((void **)&(s2)) ) + +#endif // NO_STRING_T + +//============================================================================= + +#endif // STRING_T_H diff --git a/csgo2/sdk/public/utlmap.h b/csgo2/sdk/public/utlmap.h new file mode 100644 index 0000000..3606c3f --- /dev/null +++ b/csgo2/sdk/public/utlmap.h @@ -0,0 +1,200 @@ +//========= Copyright ?1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Header: $ +// $NoKeywords: $ +//=============================================================================// + +#ifndef UTLMAP_H +#define UTLMAP_H + +#ifdef _WIN32 +#pragma once +#endif +#include "../sdk.h" +//----------------------------------------------------------------------------- +// +// Purpose: An associative container. Pretty much identical to std::map. +// +//----------------------------------------------------------------------------- + +// This is a useful macro to iterate from start to end in order in a map +#define FOR_EACH_MAP( mapName, iteratorName ) \ + for ( int iteratorName = mapName.FirstInorder(); iteratorName != mapName.InvalidIndex(); iteratorName = mapName.NextInorder( iteratorName ) ) + +// faster iteration, but in an unspecified order +#define FOR_EACH_MAP_FAST( mapName, iteratorName ) \ + for ( int iteratorName = 0; iteratorName < mapName.MaxElement(); ++iteratorName ) if ( !mapName.IsValidIndex( iteratorName ) ) continue; else + +template +class CUtlMap +{ +public: + typedef K KeyType_t; + typedef T ElemType_t; + typedef I IndexType_t; + + // Less func typedef + // Returns true if the first parameter is "less" than the second + typedef LF LessFunc_t; + + // constructor, destructor + // Left at growSize = 0, the memory will first allocate 1 element and double in size + // at each increment. + // LessFunc_t is required, but may be set after the constructor using SetLessFunc() below + CUtlMap( int growSize = 0, int initSize = 0, LessFunc_t lessfunc = 0 ) + : m_Tree( growSize, initSize, CKeyLess( lessfunc ) ) + { + } + + CUtlMap( LessFunc_t lessfunc ) + : m_Tree( CKeyLess( lessfunc ) ) + { + } + + void EnsureCapacity( int num ) { m_Tree.EnsureCapacity( num ); } + + // gets particular elements + ElemType_t & Element( IndexType_t i ) { return m_Tree.Element( i ).elem; } + const ElemType_t & Element( IndexType_t i ) const { return m_Tree.Element( i ).elem; } + ElemType_t & operator[]( IndexType_t i ) { return m_Tree.Element( i ).elem; } + const ElemType_t & operator[]( IndexType_t i ) const { return m_Tree.Element( i ).elem; } + KeyType_t & Key( IndexType_t i ) { return m_Tree.Element( i ).key; } + const KeyType_t & Key( IndexType_t i ) const { return m_Tree.Element( i ).key; } + + + // Num elements + unsigned int Count() const { return m_Tree.Count(); } + + // Max "size" of the vector + IndexType_t MaxElement() const { return m_Tree.MaxElement(); } + + // Checks if a node is valid and in the map + bool IsValidIndex( IndexType_t i ) const { return m_Tree.IsValidIndex( i ); } + + // Checks if the map as a whole is valid + bool IsValid() const { return m_Tree.IsValid(); } + + // Invalid index + static IndexType_t InvalidIndex() { return CTree::InvalidIndex(); } + + // Sets the less func + void SetLessFunc( LessFunc_t func ) + { + m_Tree.SetLessFunc( CKeyLess( func ) ); + } + + // Insert method (inserts in order) + IndexType_t Insert( const KeyType_t &key, const ElemType_t &insert ) + { + Node_t node; + node.key = key; + node.elem = insert; + return m_Tree.Insert( node ); + } + + IndexType_t Insert( const KeyType_t &key ) + { + Node_t node; + node.key = key; + return m_Tree.Insert( node ); + } + + // Find method + IndexType_t Find( const KeyType_t &key ) const + { + Node_t dummyNode; + dummyNode.key = key; + return m_Tree.Find( dummyNode ); + } + + // Remove methods + void RemoveAt( IndexType_t i ) { m_Tree.RemoveAt( i ); } + bool Remove( const KeyType_t &key ) + { + Node_t dummyNode; + dummyNode.key = key; + return m_Tree.Remove( dummyNode ); + } + + void RemoveAll( ) { m_Tree.RemoveAll(); } + void Purge( ) { m_Tree.Purge(); } + + // Iteration + IndexType_t FirstInorder() const { return m_Tree.FirstInorder(); } + IndexType_t NextInorder( IndexType_t i ) const { return m_Tree.NextInorder( i ); } + IndexType_t PrevInorder( IndexType_t i ) const { return m_Tree.PrevInorder( i ); } + IndexType_t LastInorder() const { return m_Tree.LastInorder(); } + + // If you change the search key, this can be used to reinsert the + // element into the map. + void Reinsert( const KeyType_t &key, IndexType_t i ) + { + m_Tree[i].key = key; + m_Tree.Reinsert(i); + } + + IndexType_t InsertOrReplace( const KeyType_t &key, const ElemType_t &insert ) + { + IndexType_t i = Find( key ); + if ( i != InvalidIndex() ) + { + Element( i ) = insert; + return i; + } + + return Insert( key, insert ); + } + + void Swap( CUtlMap< K, T, I > &that ) + { + m_Tree.Swap( that.m_Tree ); + } + + + struct Node_t + { + Node_t() + { + } + + Node_t( const Node_t &from ) + : key( from.key ), + elem( from.elem ) + { + } + + KeyType_t key; + ElemType_t elem; + }; + + class CKeyLess + { + public: + CKeyLess( LessFunc_t lessFunc ) : m_LessFunc(lessFunc) {} + + bool operator!() const + { + return !m_LessFunc; + } + + bool operator()( const Node_t &left, const Node_t &right ) const + { + return m_LessFunc( left.key, right.key ); + } + + LessFunc_t m_LessFunc; + }; + + typedef CUtlRBTree CTree; + + CTree *AccessTree() { return &m_Tree; } + +protected: + CTree m_Tree; +}; + +//----------------------------------------------------------------------------- + +#endif // UTLMAP_H diff --git a/csgo2/sdk/public/utlrbtree.h b/csgo2/sdk/public/utlrbtree.h new file mode 100644 index 0000000..1cf8fae --- /dev/null +++ b/csgo2/sdk/public/utlrbtree.h @@ -0,0 +1,1546 @@ +//========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Header: $ +// $NoKeywords: $ +//=============================================================================// + +#ifndef UTLRBTREE_H +#define UTLRBTREE_H + +#define Assert +// This is a useful macro to iterate from start to end in order in a map +#define FOR_EACH_UTLRBTREE( treeName, iteratorName ) \ + for ( int iteratorName = treeName.FirstInorder(); iteratorName != treeName.InvalidIndex(); iteratorName = treeName.NextInorder( iteratorName ) ) + + +//----------------------------------------------------------------------------- +// Tool to generate a default compare function for any type that implements +// operator<, including all simple types +//----------------------------------------------------------------------------- + +template +class CDefOps +{ +public: + static bool LessFunc( const T &lhs, const T &rhs ) { return ( lhs < rhs ); } +}; + +#define DefLessFunc( type ) CDefOps< type >::LessFunc + +//------------------------------------- + +inline bool StringLessThan( const char * const &lhs, const char * const &rhs) { return ( strcmp( lhs, rhs) < 0 ); } +inline bool CaselessStringLessThan( const char * const &lhs, const char * const &rhs ) { return ( _stricmp( lhs, rhs) < 0 ); } + + +// Same as CaselessStringLessThan, but it ignores differences in / and \. +inline bool CaselessStringLessThanIgnoreSlashes( const char * const &lhs, const char * const &rhs ) +{ + const char *pa = lhs; + const char *pb = rhs; + while ( *pa && *pb ) + { + char a = *pa; + char b = *pb; + + // Check for dir slashes. + if ( a == '/' || a == '\\' ) + { + if ( b != '/' && b != '\\' ) + return ('/' < b); + } + else + { + if ( a >= 'a' && a <= 'z' ) + a = 'A' + (a - 'a'); + + if ( b >= 'a' && b <= 'z' ) + b = 'A' + (b - 'a'); + + if ( a > b ) + return false; + else if ( a < b ) + return true; + } + ++pa; + ++pb; + } + + // Filenames also must be the same length. + if ( *pa != *pb ) + { + // If pa shorter than pb then it's "less" + return ( !*pa ); + } + + return false; +} + +//------------------------------------- +// inline these two templates to stop multiple definitions of the same code +template <> inline bool CDefOps::LessFunc( const char * const &lhs, const char * const &rhs ) { return StringLessThan( lhs, rhs ); } +template <> inline bool CDefOps::LessFunc( char * const &lhs, char * const &rhs ) { return StringLessThan( lhs, rhs ); } + +//------------------------------------- + +template +void SetDefLessFunc( RBTREE_T &RBTree ) +{ + RBTree.SetLessFunc( DefLessFunc( typename RBTREE_T::KeyType_t ) ); +} + +//----------------------------------------------------------------------------- +// A red-black binary search tree +//----------------------------------------------------------------------------- + +template < class I > +struct UtlRBTreeLinks_t +{ + I m_Left; + I m_Right; + I m_Parent; + I m_Tag; +}; + +template < class T, class I > +struct UtlRBTreeNode_t : public UtlRBTreeLinks_t< I > +{ + T m_Data; +}; + +template < class T, class I = unsigned short, typename L = bool (*)( const T &, const T & ), class M = CUtlMemory< UtlRBTreeNode_t< T, I >, I > > +class CUtlRBTree +{ +public: + + typedef T KeyType_t; + typedef T ElemType_t; + typedef I IndexType_t; + + // Less func typedef + // Returns true if the first parameter is "less" than the second + typedef L LessFunc_t; + + // constructor, destructor + // Left at growSize = 0, the memory will first allocate 1 element and double in size + // at each increment. + // LessFunc_t is required, but may be set after the constructor using SetLessFunc() below + CUtlRBTree( int growSize = 0, int initSize = 0, const LessFunc_t &lessfunc = 0 ); + CUtlRBTree( const LessFunc_t &lessfunc ); + ~CUtlRBTree( ); + + void EnsureCapacity( int num ); + + void CopyFrom( const CUtlRBTree &other ); + + // gets particular elements + T& Element( I i ); + T const &Element( I i ) const; + T& operator[]( I i ); + T const &operator[]( I i ) const; + + // Gets the root + I Root() const; + + // Num elements + unsigned int Count() const; + + // Max "size" of the vector + // it's not generally safe to iterate from index 0 to MaxElement()-1 + // it IS safe to do so when using CUtlMemory as the allocator, + // but we should really remove patterns using this anyways, for safety and generality + I MaxElement() const; + + // Gets the children + I Parent( I i ) const; + I LeftChild( I i ) const; + I RightChild( I i ) const; + + // Tests if a node is a left or right child + bool IsLeftChild( I i ) const; + bool IsRightChild( I i ) const; + + // Tests if root or leaf + bool IsRoot( I i ) const; + bool IsLeaf( I i ) const; + + // Checks if a node is valid and in the tree + bool IsValidIndex( I i ) const; + + // Checks if the tree as a whole is valid + bool IsValid() const; + + // Invalid index + static I InvalidIndex(); + + // returns the tree depth (not a very fast operation) + int Depth( I node ) const; + int Depth() const; + + // Sets the less func + void SetLessFunc( const LessFunc_t &func ); + + // Allocation method + I NewNode(); + + // Insert method (inserts in order) + I Insert( T const &insert ); + void Insert( const T *pArray, int nItems ); + I InsertIfNotFound( T const &insert ); + + // Find method + I Find( T const &search ) const; + + // Remove methods + void RemoveAt( I i ); + bool Remove( T const &remove ); + void RemoveAll( ); + void Purge(); + + // Allocation, deletion + void FreeNode( I i ); + + // Iteration + I FirstInorder() const; + I NextInorder( I i ) const; + I PrevInorder( I i ) const; + I LastInorder() const; + + I FirstPreorder() const; + I NextPreorder( I i ) const; + I PrevPreorder( I i ) const; + I LastPreorder( ) const; + + I FirstPostorder() const; + I NextPostorder( I i ) const; + + // If you change the search key, this can be used to reinsert the + // element into the tree. + void Reinsert( I elem ); + + // swap in place + void Swap( CUtlRBTree< T, I, L > &that ); + +private: + // Can't copy the tree this way! + CUtlRBTree& operator=( const CUtlRBTree &other ); + +protected: + enum NodeColor_t + { + RED = 0, + BLACK + }; + + typedef UtlRBTreeNode_t< T, I > Node_t; + typedef UtlRBTreeLinks_t< I > Links_t; + + // Sets the children + void SetParent( I i, I parent ); + void SetLeftChild( I i, I child ); + void SetRightChild( I i, I child ); + void LinkToParent( I i, I parent, bool isLeft ); + + // Gets at the links + Links_t const &Links( I i ) const; + Links_t &Links( I i ); + + // Checks if a link is red or black + bool IsRed( I i ) const; + bool IsBlack( I i ) const; + + // Sets/gets node color + NodeColor_t Color( I i ) const; + void SetColor( I i, NodeColor_t c ); + + // operations required to preserve tree balance + void RotateLeft(I i); + void RotateRight(I i); + void InsertRebalance(I i); + void RemoveRebalance(I i); + + // Insertion, removal + I InsertAt( I parent, bool leftchild ); + + // copy constructors not allowed + CUtlRBTree( CUtlRBTree const &tree ); + + // Inserts a node into the tree, doesn't copy the data in. + void FindInsertionPosition( T const &insert, I &parent, bool &leftchild ); + + // Remove and add back an element in the tree. + void Unlink( I elem ); + void Link( I elem ); + + // Used for sorting. + LessFunc_t m_LessFunc; + + M m_Elements; + I m_Root; + I m_NumElements; + I m_FirstFree; + typename M::Iterator_t m_LastAlloc; // the last index allocated + + int m_nAllocationCount; + int m_nGrowSize; + + FORCEINLINE M const &Elements( void ) const + { + return m_Elements; + } +}; + +// this is kind of ugly, but until C++ gets templatized typedefs in C++0x, it's our only choice +template < class T, class I = int, typename L = bool (*)( const T &, const T & ) > +class CUtlFixedRBTree : public CUtlRBTree< T, I, L, CUtlFixedMemory< UtlRBTreeNode_t< T, I > > > +{ +public: + + typedef L LessFunc_t; + + CUtlFixedRBTree( int growSize = 0, int initSize = 0, const LessFunc_t &lessfunc = 0 ) + : CUtlRBTree< T, I, L, CUtlFixedMemory< UtlRBTreeNode_t< T, I > > >( growSize, initSize, lessfunc ) {} + CUtlFixedRBTree( const LessFunc_t &lessfunc ) + : CUtlRBTree< T, I, L, CUtlFixedMemory< UtlRBTreeNode_t< T, I > > >( lessfunc ) {} + + typedef CUtlRBTree< T, I, L, CUtlFixedMemory< UtlRBTreeNode_t< T, I > > > BaseClass; + bool IsValidIndex( I i ) const + { + if ( !BaseClass::Elements().IsIdxValid( i ) ) + return false; + +#ifdef _DEBUG // it's safe to skip this here, since the only way to get indices after m_LastAlloc is to use MaxElement() + if ( BaseClass::Elements().IsIdxAfter( i, this->m_LastAlloc ) ) + { + return false; // don't read values that have been allocated, but not constructed + } +#endif + + return LeftChild(i) != i; + } + +private: + // this doesn't make sense for fixed rbtrees, since there's no useful max pointer, and the index space isn't contiguous anyways + I MaxElement() const; +}; + +// this is kind of ugly, but until C++ gets templatized typedefs in C++0x, it's our only choice +template < class T, class I = unsigned short, typename L = bool (*)( const T &, const T & ) > +class CUtlBlockRBTree : public CUtlRBTree< T, I, L, CUtlBlockMemory< UtlRBTreeNode_t< T, I >, I > > +{ +public: + typedef L LessFunc_t; + CUtlBlockRBTree( int growSize = 0, int initSize = 0, const LessFunc_t &lessfunc = 0 ) + : CUtlRBTree< T, I, L, CUtlBlockMemory< UtlRBTreeNode_t< T, I >, I > >( growSize, initSize, lessfunc ) {} + CUtlBlockRBTree( const LessFunc_t &lessfunc ) + : CUtlRBTree< T, I, L, CUtlBlockMemory< UtlRBTreeNode_t< T, I >, I > >( lessfunc ) {} +}; + + +//----------------------------------------------------------------------------- +// constructor, destructor +//----------------------------------------------------------------------------- + +template < class T, class I, typename L, class M > +inline CUtlRBTree::CUtlRBTree( int growSize, int initSize, const LessFunc_t &lessfunc ) : +m_LessFunc( lessfunc ), +m_Elements( growSize, initSize ), +m_Root( InvalidIndex() ), +m_NumElements( 0 ), +m_FirstFree( InvalidIndex() ), +m_LastAlloc( m_Elements.InvalidIterator() ) +{ +} + +template < class T, class I, typename L, class M > +inline CUtlRBTree::CUtlRBTree( const LessFunc_t &lessfunc ) : +m_LessFunc( lessfunc ), +m_Elements( 0, 0 ), +m_Root( InvalidIndex() ), +m_NumElements( 0 ), +m_FirstFree( InvalidIndex() ), +m_LastAlloc( m_Elements.InvalidIterator() ) +{ +} + +template < class T, class I, typename L, class M > +inline CUtlRBTree::~CUtlRBTree() +{ + Purge(); +} + +template < class T, class I, typename L, class M > +inline void CUtlRBTree::EnsureCapacity( int num ) +{ + m_Elements.EnsureCapacity( num ); +} + +template < class T, class I, typename L, class M > +inline void CUtlRBTree::CopyFrom( const CUtlRBTree &other ) +{ + Purge(); + m_Elements.EnsureCapacity( other.m_Elements.Count() ); + memcpy( m_Elements.Base(), other.m_Elements.Base(), other.m_Elements.Count() * sizeof( UtlRBTreeNode_t< T, I > ) ); + m_LessFunc = other.m_LessFunc; + m_Root = other.m_Root; + m_NumElements = other.m_NumElements; + m_FirstFree = other.m_FirstFree; + m_LastAlloc = other.m_LastAlloc; +} + +//----------------------------------------------------------------------------- +// gets particular elements +//----------------------------------------------------------------------------- + +template < class T, class I, typename L, class M > +inline T &CUtlRBTree::Element( I i ) +{ + return m_Elements[i].m_Data; +} + +template < class T, class I, typename L, class M > +inline T const &CUtlRBTree::Element( I i ) const +{ + return m_Elements[i].m_Data; +} + +template < class T, class I, typename L, class M > +inline T &CUtlRBTree::operator[]( I i ) +{ + return Element(i); +} + +template < class T, class I, typename L, class M > +inline T const &CUtlRBTree::operator[]( I i ) const +{ + return Element(i); +} + +//----------------------------------------------------------------------------- +// +// various accessors +// +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// Gets the root +//----------------------------------------------------------------------------- + +template < class T, class I, typename L, class M > +inline I CUtlRBTree::Root() const +{ + return m_Root; +} + +//----------------------------------------------------------------------------- +// Num elements +//----------------------------------------------------------------------------- + +template < class T, class I, typename L, class M > +inline unsigned int CUtlRBTree::Count() const +{ + return (unsigned int)m_NumElements; +} + +//----------------------------------------------------------------------------- +// Max "size" of the vector +//----------------------------------------------------------------------------- + +template < class T, class I, typename L, class M > +inline I CUtlRBTree::MaxElement() const +{ + return ( I )m_Elements.NumAllocated(); +} + + +//----------------------------------------------------------------------------- +// Gets the children +//----------------------------------------------------------------------------- + +template < class T, class I, typename L, class M > +inline I CUtlRBTree::Parent( I i ) const +{ + return Links(i).m_Parent; +} + +template < class T, class I, typename L, class M > +inline I CUtlRBTree::LeftChild( I i ) const +{ + return Links(i).m_Left; +} + +template < class T, class I, typename L, class M > +inline I CUtlRBTree::RightChild( I i ) const +{ + return Links(i).m_Right; +} + +//----------------------------------------------------------------------------- +// Tests if a node is a left or right child +//----------------------------------------------------------------------------- + +template < class T, class I, typename L, class M > +inline bool CUtlRBTree::IsLeftChild( I i ) const +{ + return LeftChild(Parent(i)) == i; +} + +template < class T, class I, typename L, class M > +inline bool CUtlRBTree::IsRightChild( I i ) const +{ + return RightChild(Parent(i)) == i; +} + + +//----------------------------------------------------------------------------- +// Tests if root or leaf +//----------------------------------------------------------------------------- + +template < class T, class I, typename L, class M > +inline bool CUtlRBTree::IsRoot( I i ) const +{ + return i == m_Root; +} + +template < class T, class I, typename L, class M > +inline bool CUtlRBTree::IsLeaf( I i ) const +{ + return (LeftChild(i) == InvalidIndex()) && (RightChild(i) == InvalidIndex()); +} + + +//----------------------------------------------------------------------------- +// Checks if a node is valid and in the tree +//----------------------------------------------------------------------------- + +template < class T, class I, typename L, class M > +inline bool CUtlRBTree::IsValidIndex( I i ) const +{ + if ( !m_Elements.IsIdxValid( i ) ) + return false; + + if ( m_Elements.IsIdxAfter( i, m_LastAlloc ) ) + return false; // don't read values that have been allocated, but not constructed + + return LeftChild(i) != i; +} + + +//----------------------------------------------------------------------------- +// Invalid index +//----------------------------------------------------------------------------- + +template < class T, class I, typename L, class M > +inline I CUtlRBTree::InvalidIndex() +{ + return ( I )M::InvalidIndex(); +} + + +//----------------------------------------------------------------------------- +// returns the tree depth (not a very fast operation) +//----------------------------------------------------------------------------- + +template < class T, class I, typename L, class M > +inline int CUtlRBTree::Depth() const +{ + return Depth(Root()); +} + +//----------------------------------------------------------------------------- +// Sets the children +//----------------------------------------------------------------------------- + +template < class T, class I, typename L, class M > +inline void CUtlRBTree::SetParent( I i, I parent ) +{ + Links(i).m_Parent = parent; +} + +template < class T, class I, typename L, class M > +inline void CUtlRBTree::SetLeftChild( I i, I child ) +{ + Links(i).m_Left = child; +} + +template < class T, class I, typename L, class M > +inline void CUtlRBTree::SetRightChild( I i, I child ) +{ + Links(i).m_Right = child; +} + +//----------------------------------------------------------------------------- +// Gets at the links +//----------------------------------------------------------------------------- + +template < class T, class I, typename L, class M > +inline typename CUtlRBTree::Links_t const &CUtlRBTree::Links( I i ) const +{ + // Sentinel node, makes life easier + static Links_t s_Sentinel = + { + InvalidIndex(), InvalidIndex(), InvalidIndex(), CUtlRBTree::BLACK + }; + + return (i != InvalidIndex()) ? *(Links_t*)&m_Elements[i] : *(Links_t*)&s_Sentinel; +} + +template < class T, class I, typename L, class M > +inline typename CUtlRBTree::Links_t &CUtlRBTree::Links( I i ) +{ + return *(Links_t *)&m_Elements[i]; +} + +//----------------------------------------------------------------------------- +// Checks if a link is red or black +//----------------------------------------------------------------------------- + +template < class T, class I, typename L, class M > +inline bool CUtlRBTree::IsRed( I i ) const +{ + return (Links(i).m_Tag == RED); +} + +template < class T, class I, typename L, class M > +inline bool CUtlRBTree::IsBlack( I i ) const +{ + return (Links(i).m_Tag == BLACK); +} + + +//----------------------------------------------------------------------------- +// Sets/gets node color +//----------------------------------------------------------------------------- + +template < class T, class I, typename L, class M > +inline typename CUtlRBTree::NodeColor_t CUtlRBTree::Color( I i ) const +{ + return (NodeColor_t)Links(i).m_Tag; +} + +template < class T, class I, typename L, class M > +inline void CUtlRBTree::SetColor( I i, typename CUtlRBTree::NodeColor_t c ) +{ + Links(i).m_Tag = (I)c; +} + +//----------------------------------------------------------------------------- +// Allocates/ deallocates nodes +//----------------------------------------------------------------------------- +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable:4389) // '==' : signed/unsigned mismatch +#endif +template < class T, class I, typename L, class M > +I CUtlRBTree::NewNode() +{ + I elem; + + // Nothing in the free list; add. + if ( m_FirstFree == InvalidIndex() ) + { + typename M::Iterator_t it = m_Elements.IsValidIterator( m_LastAlloc ) ? m_Elements.Next( m_LastAlloc ) : m_Elements.First(); + if ( !m_Elements.IsValidIterator( it ) ) + { + MEM_ALLOC_CREDIT_CLASS(); + m_Elements.Grow(); + + it = m_Elements.IsValidIterator( m_LastAlloc ) ? m_Elements.Next( m_LastAlloc ) : m_Elements.First(); + + if ( !m_Elements.IsValidIterator( it ) ) + { + __debugbreak(); + } + } + m_LastAlloc = it; + elem = m_Elements.GetIndex( m_LastAlloc ); + } + else + { + elem = m_FirstFree; + m_FirstFree = Links( m_FirstFree ).m_Right; + } + +#ifdef _DEBUG + // reset links to invalid.... + Links_t &node = Links( elem ); + node.m_Left = node.m_Right = node.m_Parent = InvalidIndex(); +#endif + + Construct( &Element( elem ) ); + + return elem; +} +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +template < class T, class I, typename L, class M > +void CUtlRBTree::FreeNode( I i ) +{ + Assert( IsValidIndex(i) && (i != InvalidIndex()) ); + Destruct( &Element(i) ); + SetLeftChild( i, i ); // indicates it's in not in the tree + SetRightChild( i, m_FirstFree ); + m_FirstFree = i; +} + + +//----------------------------------------------------------------------------- +// Rotates node i to the left +//----------------------------------------------------------------------------- + +template < class T, class I, typename L, class M > +void CUtlRBTree::RotateLeft(I elem) +{ + I rightchild = RightChild(elem); + SetRightChild( elem, LeftChild(rightchild) ); + if (LeftChild(rightchild) != InvalidIndex()) + SetParent( LeftChild(rightchild), elem ); + + if (rightchild != InvalidIndex()) + SetParent( rightchild, Parent(elem) ); + if (!IsRoot(elem)) + { + if (IsLeftChild(elem)) + SetLeftChild( Parent(elem), rightchild ); + else + SetRightChild( Parent(elem), rightchild ); + } + else + m_Root = rightchild; + + SetLeftChild( rightchild, elem ); + if (elem != InvalidIndex()) + SetParent( elem, rightchild ); +} + + +//----------------------------------------------------------------------------- +// Rotates node i to the right +//----------------------------------------------------------------------------- + +template < class T, class I, typename L, class M > +void CUtlRBTree::RotateRight(I elem) +{ + I leftchild = LeftChild(elem); + SetLeftChild( elem, RightChild(leftchild) ); + if (RightChild(leftchild) != InvalidIndex()) + SetParent( RightChild(leftchild), elem ); + + if (leftchild != InvalidIndex()) + SetParent( leftchild, Parent(elem) ); + if (!IsRoot(elem)) + { + if (IsRightChild(elem)) + SetRightChild( Parent(elem), leftchild ); + else + SetLeftChild( Parent(elem), leftchild ); + } + else + m_Root = leftchild; + + SetRightChild( leftchild, elem ); + if (elem != InvalidIndex()) + SetParent( elem, leftchild ); +} + + +//----------------------------------------------------------------------------- +// Rebalances the tree after an insertion +//----------------------------------------------------------------------------- + +template < class T, class I, typename L, class M > +void CUtlRBTree::InsertRebalance(I elem) +{ + while ( !IsRoot(elem) && (Color(Parent(elem)) == RED) ) + { + I parent = Parent(elem); + I grandparent = Parent(parent); + + /* we have a violation */ + if (IsLeftChild(parent)) + { + I uncle = RightChild(grandparent); + if (IsRed(uncle)) + { + /* uncle is RED */ + SetColor(parent, BLACK); + SetColor(uncle, BLACK); + SetColor(grandparent, RED); + elem = grandparent; + } + else + { + /* uncle is BLACK */ + if (IsRightChild(elem)) + { + /* make x a left child, will change parent and grandparent */ + elem = parent; + RotateLeft(elem); + parent = Parent(elem); + grandparent = Parent(parent); + } + /* recolor and rotate */ + SetColor(parent, BLACK); + SetColor(grandparent, RED); + RotateRight(grandparent); + } + } + else + { + /* mirror image of above code */ + I uncle = LeftChild(grandparent); + if (IsRed(uncle)) + { + /* uncle is RED */ + SetColor(parent, BLACK); + SetColor(uncle, BLACK); + SetColor(grandparent, RED); + elem = grandparent; + } + else + { + /* uncle is BLACK */ + if (IsLeftChild(elem)) + { + /* make x a right child, will change parent and grandparent */ + elem = parent; + RotateRight(parent); + parent = Parent(elem); + grandparent = Parent(parent); + } + /* recolor and rotate */ + SetColor(parent, BLACK); + SetColor(grandparent, RED); + RotateLeft(grandparent); + } + } + } + SetColor( m_Root, BLACK ); +} + + +//----------------------------------------------------------------------------- +// Insert a node into the tree +//----------------------------------------------------------------------------- + +template < class T, class I, typename L, class M > +I CUtlRBTree::InsertAt( I parent, bool leftchild ) +{ + I i = NewNode(); + LinkToParent( i, parent, leftchild ); + ++m_NumElements; + + return i; +} + +template < class T, class I, typename L, class M > +void CUtlRBTree::LinkToParent( I i, I parent, bool isLeft ) +{ + Links_t &elem = Links(i); + elem.m_Parent = parent; + elem.m_Left = elem.m_Right = InvalidIndex(); + elem.m_Tag = RED; + + /* insert node in tree */ + if (parent != InvalidIndex()) + { + if (isLeft) + Links(parent).m_Left = i; + else + Links(parent).m_Right = i; + } + else + { + m_Root = i; + } + + InsertRebalance(i); +} + +//----------------------------------------------------------------------------- +// Rebalance the tree after a deletion +//----------------------------------------------------------------------------- + +template < class T, class I, typename L, class M > +void CUtlRBTree::RemoveRebalance(I elem) +{ + while (elem != m_Root && IsBlack(elem)) + { + I parent = Parent(elem); + + // If elem is the left child of the parent + if (elem == LeftChild(parent)) + { + // Get our sibling + I sibling = RightChild(parent); + if (IsRed(sibling)) + { + SetColor(sibling, BLACK); + SetColor(parent, RED); + RotateLeft(parent); + + // We may have a new parent now + parent = Parent(elem); + sibling = RightChild(parent); + } + if ( (IsBlack(LeftChild(sibling))) && (IsBlack(RightChild(sibling))) ) + { + if (sibling != InvalidIndex()) + SetColor(sibling, RED); + elem = parent; + } + else + { + if (IsBlack(RightChild(sibling))) + { + SetColor(LeftChild(sibling), BLACK); + SetColor(sibling, RED); + RotateRight(sibling); + + // rotation may have changed this + parent = Parent(elem); + sibling = RightChild(parent); + } + SetColor( sibling, Color(parent) ); + SetColor( parent, BLACK ); + SetColor( RightChild(sibling), BLACK ); + RotateLeft( parent ); + elem = m_Root; + } + } + else + { + // Elem is the right child of the parent + I sibling = LeftChild(parent); + if (IsRed(sibling)) + { + SetColor(sibling, BLACK); + SetColor(parent, RED); + RotateRight(parent); + + // We may have a new parent now + parent = Parent(elem); + sibling = LeftChild(parent); + } + if ( (IsBlack(RightChild(sibling))) && (IsBlack(LeftChild(sibling))) ) + { + if (sibling != InvalidIndex()) + SetColor( sibling, RED ); + elem = parent; + } + else + { + if (IsBlack(LeftChild(sibling))) + { + SetColor( RightChild(sibling), BLACK ); + SetColor( sibling, RED ); + RotateLeft( sibling ); + + // rotation may have changed this + parent = Parent(elem); + sibling = LeftChild(parent); + } + SetColor( sibling, Color(parent) ); + SetColor( parent, BLACK ); + SetColor( LeftChild(sibling), BLACK ); + RotateRight( parent ); + elem = m_Root; + } + } + } + SetColor( elem, BLACK ); +} + +template < class T, class I, typename L, class M > +void CUtlRBTree::Unlink( I elem ) +{ + if ( elem != InvalidIndex() ) + { + I x, y; + + if ((LeftChild(elem) == InvalidIndex()) || + (RightChild(elem) == InvalidIndex())) + { + /* y has a NIL node as a child */ + y = elem; + } + else + { + /* find tree successor with a NIL node as a child */ + y = RightChild(elem); + while (LeftChild(y) != InvalidIndex()) + y = LeftChild(y); + } + + /* x is y's only child */ + if (LeftChild(y) != InvalidIndex()) + x = LeftChild(y); + else + x = RightChild(y); + + /* remove y from the parent chain */ + if (x != InvalidIndex()) + SetParent( x, Parent(y) ); + if (!IsRoot(y)) + { + if (IsLeftChild(y)) + SetLeftChild( Parent(y), x ); + else + SetRightChild( Parent(y), x ); + } + else + m_Root = x; + + // need to store this off now, we'll be resetting y's color + NodeColor_t ycolor = Color(y); + if (y != elem) + { + // Standard implementations copy the data around, we cannot here. + // Hook in y to link to the same stuff elem used to. + SetParent( y, Parent(elem) ); + SetRightChild( y, RightChild(elem) ); + SetLeftChild( y, LeftChild(elem) ); + + if (!IsRoot(elem)) + if (IsLeftChild(elem)) + SetLeftChild( Parent(elem), y ); + else + SetRightChild( Parent(elem), y ); + else + m_Root = y; + + if (LeftChild(y) != InvalidIndex()) + SetParent( LeftChild(y), y ); + if (RightChild(y) != InvalidIndex()) + SetParent( RightChild(y), y ); + + SetColor( y, Color(elem) ); + } + + if ((x != InvalidIndex()) && (ycolor == BLACK)) + RemoveRebalance(x); + } +} + +template < class T, class I, typename L, class M > +void CUtlRBTree::Link( I elem ) +{ + if ( elem != InvalidIndex() ) + { + I parent; + bool leftchild; + + FindInsertionPosition( Element( elem ), parent, leftchild ); + + LinkToParent( elem, parent, leftchild ); + + Assert(IsValid()); + } +} + +//----------------------------------------------------------------------------- +// Delete a node from the tree +//----------------------------------------------------------------------------- + +template < class T, class I, typename L, class M > +void CUtlRBTree::RemoveAt(I elem) +{ + if ( elem != InvalidIndex() ) + { + Unlink( elem ); + + FreeNode(elem); + --m_NumElements; + + Assert(IsValid()); + } +} + + +//----------------------------------------------------------------------------- +// remove a node in the tree +//----------------------------------------------------------------------------- + +template < class T, class I, typename L, class M > bool CUtlRBTree::Remove( T const &search ) +{ + I node = Find( search ); + if (node != InvalidIndex()) + { + RemoveAt(node); + return true; + } + return false; +} + + +//----------------------------------------------------------------------------- +// Removes all nodes from the tree +//----------------------------------------------------------------------------- + +template < class T, class I, typename L, class M > +void CUtlRBTree::RemoveAll() +{ + // Have to do some convoluted stuff to invoke the destructor on all + // valid elements for the multilist case (since we don't have all elements + // connected to each other in a list). + + if ( m_LastAlloc == m_Elements.InvalidIterator() ) + { + Assert( m_Root == InvalidIndex() ); + Assert( m_FirstFree == InvalidIndex() ); + Assert( m_NumElements == 0 ); + return; + } + + for ( typename M::Iterator_t it = m_Elements.First(); it != m_Elements.InvalidIterator(); it = m_Elements.Next( it ) ) + { + I i = m_Elements.GetIndex( it ); + if ( IsValidIndex( i ) ) // skip elements in the free list + { + Destruct( &Element( i ) ); + SetRightChild( i, m_FirstFree ); + SetLeftChild( i, i ); + m_FirstFree = i; + } + + if ( it == m_LastAlloc ) + break; // don't destruct elements that haven't ever been constucted + } + + // Clear everything else out + m_Root = InvalidIndex(); + m_NumElements = 0; + + Assert( IsValid() ); +} + +//----------------------------------------------------------------------------- +// Removes all nodes from the tree and purges memory +//----------------------------------------------------------------------------- + +template < class T, class I, typename L, class M > +void CUtlRBTree::Purge() +{ + RemoveAll(); + m_FirstFree = InvalidIndex(); + m_Elements.Purge(); + m_LastAlloc = m_Elements.InvalidIterator(); +} + + +//----------------------------------------------------------------------------- +// iteration +//----------------------------------------------------------------------------- + +template < class T, class I, typename L, class M > +I CUtlRBTree::FirstInorder() const +{ + I i = m_Root; + while (LeftChild(i) != InvalidIndex()) + i = LeftChild(i); + return i; +} + +template < class T, class I, typename L, class M > +I CUtlRBTree::NextInorder( I i ) const +{ + Assert(IsValidIndex(i)); + + if (RightChild(i) != InvalidIndex()) + { + i = RightChild(i); + while (LeftChild(i) != InvalidIndex()) + i = LeftChild(i); + return i; + } + + I parent = Parent(i); + while (IsRightChild(i)) + { + i = parent; + if (i == InvalidIndex()) break; + parent = Parent(i); + } + return parent; +} + +template < class T, class I, typename L, class M > +I CUtlRBTree::PrevInorder( I i ) const +{ + Assert(IsValidIndex(i)); + + if (LeftChild(i) != InvalidIndex()) + { + i = LeftChild(i); + while (RightChild(i) != InvalidIndex()) + i = RightChild(i); + return i; + } + + I parent = Parent(i); + while (IsLeftChild(i)) + { + i = parent; + if (i == InvalidIndex()) break; + parent = Parent(i); + } + return parent; +} + +template < class T, class I, typename L, class M > +I CUtlRBTree::LastInorder() const +{ + I i = m_Root; + while (RightChild(i) != InvalidIndex()) + i = RightChild(i); + return i; +} + +template < class T, class I, typename L, class M > +I CUtlRBTree::FirstPreorder() const +{ + return m_Root; +} + +template < class T, class I, typename L, class M > +I CUtlRBTree::NextPreorder( I i ) const +{ + if (LeftChild(i) != InvalidIndex()) + return LeftChild(i); + + if (RightChild(i) != InvalidIndex()) + return RightChild(i); + + I parent = Parent(i); + while( parent != InvalidIndex()) + { + if (IsLeftChild(i) && (RightChild(parent) != InvalidIndex())) + return RightChild(parent); + i = parent; + parent = Parent(parent); + } + return InvalidIndex(); +} + +template < class T, class I, typename L, class M > +I CUtlRBTree::PrevPreorder( I i ) const +{ + Assert(0); // not implemented yet + return InvalidIndex(); +} + +template < class T, class I, typename L, class M > +I CUtlRBTree::LastPreorder() const +{ + I i = m_Root; + while (1) + { + while (RightChild(i) != InvalidIndex()) + i = RightChild(i); + + if (LeftChild(i) != InvalidIndex()) + i = LeftChild(i); + else + break; + } + return i; +} + +template < class T, class I, typename L, class M > +I CUtlRBTree::FirstPostorder() const +{ + I i = m_Root; + while (!IsLeaf(i)) + { + if (LeftChild(i)) + i = LeftChild(i); + else + i = RightChild(i); + } + return i; +} + +template < class T, class I, typename L, class M > +I CUtlRBTree::NextPostorder( I i ) const +{ + I parent = Parent(i); + if (parent == InvalidIndex()) + return InvalidIndex(); + + if (IsRightChild(i)) + return parent; + + if (RightChild(parent) == InvalidIndex()) + return parent; + + i = RightChild(parent); + while (!IsLeaf(i)) + { + if (LeftChild(i)) + i = LeftChild(i); + else + i = RightChild(i); + } + return i; +} + + +template < class T, class I, typename L, class M > +void CUtlRBTree::Reinsert( I elem ) +{ + Unlink( elem ); + Link( elem ); +} + + +//----------------------------------------------------------------------------- +// returns the tree depth (not a very fast operation) +//----------------------------------------------------------------------------- + +template < class T, class I, typename L, class M > +int CUtlRBTree::Depth( I node ) const +{ + if (node == InvalidIndex()) + return 0; + + int depthright = Depth( RightChild(node) ); + int depthleft = Depth( LeftChild(node) ); + return MAX( depthright, depthleft ) + 1; +} + + +//#define UTLTREE_PARANOID + +//----------------------------------------------------------------------------- +// Makes sure the tree is valid after every operation +//----------------------------------------------------------------------------- + +template < class T, class I, typename L, class M > +bool CUtlRBTree::IsValid() const +{ + if ( !Count() ) + return true; + + if ( m_LastAlloc == m_Elements.InvalidIterator() ) + return false; + + if ( !m_Elements.IsIdxValid( Root() ) ) + return false; + + if ( Parent( Root() ) != InvalidIndex() ) + return false; + +#ifdef UTLTREE_PARANOID + + // First check to see that mNumEntries matches reality. + // count items on the free list + int numFree = 0; + for ( int i = m_FirstFree; i != InvalidIndex(); i = RightChild( i ) ) + { + ++numFree; + if ( !m_Elements.IsIdxValid( i ) ) + return false; + } + + // iterate over all elements, looking for validity + // based on the self pointers + int nElements = 0; + int numFree2 = 0; + for ( M::Iterator_t it = m_Elements.First(); it != m_Elements.InvalidIterator(); it = m_Elements.Next( it ) ) + { + I i = m_Elements.GetIndex( it ); + if ( !IsValidIndex( i ) ) + { + ++numFree2; + } + else + { + ++nElements; + + int right = RightChild( i ); + int left = LeftChild( i ); + if ( ( right == left ) && ( right != InvalidIndex() ) ) + return false; + + if ( right != InvalidIndex() ) + { + if ( !IsValidIndex( right ) ) + return false; + if ( Parent( right ) != i ) + return false; + if ( IsRed( i ) && IsRed( right ) ) + return false; + } + + if ( left != InvalidIndex() ) + { + if ( !IsValidIndex( left ) ) + return false; + if ( Parent( left ) != i ) + return false; + if ( IsRed( i ) && IsRed( left ) ) + return false; + } + } + + if ( it == m_LastAlloc ) + break; + } + if ( numFree2 != numFree ) + return false; + + if ( nElements != m_NumElements ) + return false; + +#endif // UTLTREE_PARANOID + + return true; +} + + +//----------------------------------------------------------------------------- +// Sets the less func +//----------------------------------------------------------------------------- + +template < class T, class I, typename L, class M > +void CUtlRBTree::SetLessFunc( const typename CUtlRBTree::LessFunc_t &func ) +{ + if (!m_LessFunc) + { + m_LessFunc = func; + } + else if ( Count() > 0 ) + { + // need to re-sort the tree here.... + Assert(0); + } +} + + +//----------------------------------------------------------------------------- +// inserts a node into the tree +//----------------------------------------------------------------------------- + +// Inserts a node into the tree, doesn't copy the data in. +template < class T, class I, typename L, class M > +void CUtlRBTree::FindInsertionPosition( T const &insert, I &parent, bool &leftchild ) +{ + Assert( m_LessFunc ); + + /* find where node belongs */ + I current = m_Root; + parent = InvalidIndex(); + leftchild = false; + while (current != InvalidIndex()) + { + parent = current; + if (m_LessFunc( insert, Element(current) )) + { + leftchild = true; current = LeftChild(current); + } + else + { + leftchild = false; current = RightChild(current); + } + } +} + +template < class T, class I, typename L, class M > +I CUtlRBTree::Insert( T const &insert ) +{ + // use copy constructor to copy it in + I parent; + bool leftchild; + FindInsertionPosition( insert, parent, leftchild ); + I newNode = InsertAt( parent, leftchild ); + CopyConstruct( &Element( newNode ), insert ); + return newNode; +} + + +template < class T, class I, typename L, class M > +void CUtlRBTree::Insert( const T *pArray, int nItems ) +{ + while ( nItems-- ) + { + Insert( *pArray++ ); + } +} + + +template < class T, class I, typename L, class M > +I CUtlRBTree::InsertIfNotFound( T const &insert ) +{ + // use copy constructor to copy it in + I parent; + bool leftchild; + + I current = m_Root; + parent = InvalidIndex(); + leftchild = false; + while (current != InvalidIndex()) + { + parent = current; + if (m_LessFunc( insert, Element(current) )) + { + leftchild = true; current = LeftChild(current); + } + else if (m_LessFunc( Element(current), insert )) + { + leftchild = false; current = RightChild(current); + } + else + // Match found, no insertion + return InvalidIndex(); + } + + I newNode = InsertAt( parent, leftchild ); + CopyConstruct( &Element( newNode ), insert ); + return newNode; +} + + +//----------------------------------------------------------------------------- +// finds a node in the tree +//----------------------------------------------------------------------------- +template < class T, class I, typename L, class M > +I CUtlRBTree::Find( T const &search ) const +{ + Assert( m_LessFunc ); + + I current = m_Root; + while (current != InvalidIndex()) + { + if (m_LessFunc( search, Element(current) )) + current = LeftChild(current); + else if (m_LessFunc( Element(current), search )) + current = RightChild(current); + else + break; + } + return current; +} + + +//----------------------------------------------------------------------------- +// swap in place +//----------------------------------------------------------------------------- +template < class T, class I, typename L, class M > +void CUtlRBTree::Swap( CUtlRBTree< T, I, L > &that ) +{ + m_Elements.Swap( that.m_Elements ); + V_swap( m_LessFunc, that.m_LessFunc ); + V_swap( m_Root, that.m_Root ); + V_swap( m_NumElements, that.m_NumElements ); + V_swap( m_FirstFree, that.m_FirstFree ); + V_swap( m_LastAlloc, that.m_LastAlloc ); + Assert( IsValid() ); + Assert( m_Elements.IsValidIterator( m_LastAlloc ) || ( m_NumElements == 0 && m_FirstFree == InvalidIndex() ) ); +} + + +#endif // UTLRBTREE_H diff --git a/csgo2/sdk/sdk.h b/csgo2/sdk/sdk.h index 156d39a..9838b4d 100644 --- a/csgo2/sdk/sdk.h +++ b/csgo2/sdk/sdk.h @@ -1,4 +1,6 @@ #pragma once +#include +#include #define CORRECT_PATH_SEPARATOR '\\' #define CORRECT_PATH_SEPARATOR_S "\\" #define INCORRECT_PATH_SEPARATOR '/' @@ -29,4 +31,31 @@ enum EUniverse // k_EUniverseRC = 5, // no such universe anymore k_EUniverseMax }; + +#define Plat_FastMemset memset +#define Plat_FastMemcpy memcpy +#define RESTRICT __restrict +#define RESTRICT_FUNC __declspec(restrict) +#define FORCEINLINE_TEMPLATE __forceinline +#define PAD_NUMBER(number, boundary) \ + ( ((number) + ((boundary)-1)) / (boundary) ) * (boundary) +typedef __int64 intp; +#ifndef Assert +#define Assert +#endif // !Assert +template +inline T* Construct(T* pMemory) +{ + return ::new(pMemory) T; +} + +template +inline void Destruct(T* pMemory) +{ + pMemory->~T(); + +#ifdef _DEBUG + memset((void*)pMemory, 0xDD, sizeof(T)); +#endif +} #include "../head.h" \ No newline at end of file diff --git a/csgo2/sdk/tier1/UtlVector.hpp b/csgo2/sdk/tier1/UtlVector.hpp index 69104ba..2e77cd1 100644 --- a/csgo2/sdk/tier1/UtlVector.hpp +++ b/csgo2/sdk/tier1/UtlVector.hpp @@ -1,5 +1,5 @@ #pragma once - +#include #include #include "UtlMemory.hpp" #define _Utl_Vector_assert diff --git a/csgo2/sdk/tier1/utlblockmemory.h b/csgo2/sdk/tier1/utlblockmemory.h new file mode 100644 index 0000000..cb00e7e --- /dev/null +++ b/csgo2/sdk/tier1/utlblockmemory.h @@ -0,0 +1,345 @@ +//===== Copyright � 1996-2005, Valve Corporation, All rights reserved. ======// +// +// Purpose: +// +// $NoKeywords: $ +// +// A growable memory class. +//===========================================================================// + +#ifndef UTLBLOCKMEMORY_H +#define UTLBLOCKMEMORY_H + +#ifdef _WIN32 +#pragma once +#endif +#include "../sdk.h" + +#ifdef _MSC_VER +#pragma warning (disable:4100) +#pragma warning (disable:4514) +#endif + +//----------------------------------------------------------------------------- + +#ifdef UTBLOCKLMEMORY_TRACK +#define UTLBLOCKMEMORY_TRACK_ALLOC() MemAlloc_RegisterAllocation( "Sum of all UtlBlockMemory", 0, NumAllocated() * sizeof(T), NumAllocated() * sizeof(T), 0 ) +#define UTLBLOCKMEMORY_TRACK_FREE() if ( !m_pMemory ) ; else MemAlloc_RegisterDeallocation( "Sum of all UtlBlockMemory", 0, NumAllocated() * sizeof(T), NumAllocated() * sizeof(T), 0 ) +#else +#define UTLBLOCKMEMORY_TRACK_ALLOC() ((void)0) +#define UTLBLOCKMEMORY_TRACK_FREE() ((void)0) +#endif + + +//----------------------------------------------------------------------------- +// The CUtlBlockMemory class: +// A growable memory class that allocates non-sequential blocks, but is indexed sequentially +//----------------------------------------------------------------------------- +template< class T, class I > +class CUtlBlockMemory +{ +public: + // constructor, destructor + CUtlBlockMemory( int nGrowSize = 0, int nInitSize = 0 ); + ~CUtlBlockMemory(); + + // Set the size by which the memory grows - round up to the next power of 2 + void Init( int nGrowSize = 0, int nInitSize = 0 ); + + // here to match CUtlMemory, but not used, so it can just return NULL + T* Base() { return NULL; } + const T* Base() const { return NULL; } + + class Iterator_t + { + public: + Iterator_t( I i ) : index( i ) {} + I index; + + bool operator==( const Iterator_t it ) const { return index == it.index; } + bool operator!=( const Iterator_t it ) const { return index != it.index; } + }; + Iterator_t First() const { return Iterator_t( IsIdxValid( 0 ) ? 0 : InvalidIndex() ); } + Iterator_t Next( const Iterator_t &it ) const { return Iterator_t( IsIdxValid( it.index + 1 ) ? it.index + 1 : InvalidIndex() ); } + I GetIndex( const Iterator_t &it ) const { return it.index; } + bool IsIdxAfter( I i, const Iterator_t &it ) const { return i > it.index; } + bool IsValidIterator( const Iterator_t &it ) const { return IsIdxValid( it.index ); } + Iterator_t InvalidIterator() const { return Iterator_t( InvalidIndex() ); } + + // element access + T& operator[]( I i ); + const T& operator[]( I i ) const; + T& Element( I i ); + const T& Element( I i ) const; + + // Can we use this index? + bool IsIdxValid( I i ) const; + static I InvalidIndex() { return ( I )-1; } + + void Swap( CUtlBlockMemory< T, I > &mem ); + + // Size + int NumAllocated() const; + int Count() const { return NumAllocated(); } + + // Grows memory by max(num,growsize) rounded up to the next power of 2, and returns the allocation index/ptr + void Grow( int num = 1 ); + + // Makes sure we've got at least this much memory + void EnsureCapacity( int num ); + + // Memory deallocation + void Purge(); + + // Purge all but the given number of elements + void Purge( int numElements ); + +protected: + int Index( int major, int minor ) const { return ( major << m_nIndexShift ) | minor; } + int MajorIndex( int i ) const { return i >> m_nIndexShift; } + int MinorIndex( int i ) const { return i & m_nIndexMask; } + void ChangeSize( int nBlocks ); + int NumElementsInBlock() const { return m_nIndexMask + 1; } + + T** m_pMemory; + int m_nBlocks; + int m_nIndexMask : 27; + int m_nIndexShift : 5; +}; + +//----------------------------------------------------------------------------- +// constructor, destructor +//----------------------------------------------------------------------------- + +template< class T, class I > +CUtlBlockMemory::CUtlBlockMemory( int nGrowSize, int nInitAllocationCount ) +: m_pMemory( 0 ), m_nBlocks( 0 ), m_nIndexMask( 0 ), m_nIndexShift( 0 ) +{ + Init( nGrowSize, nInitAllocationCount ); +} + +template< class T, class I > +CUtlBlockMemory::~CUtlBlockMemory() +{ + Purge(); +} + + +//----------------------------------------------------------------------------- +// Fast swap +//----------------------------------------------------------------------------- +template< class T, class I > +void CUtlBlockMemory::Swap( CUtlBlockMemory< T, I > &mem ) +{ + V_swap( m_pMemory, mem.m_pMemory ); + V_swap( m_nBlocks, mem.m_nBlocks ); + V_swap( m_nIndexMask, mem.m_nIndexMask ); + V_swap( m_nIndexShift, mem.m_nIndexShift ); +} + + +//----------------------------------------------------------------------------- +// Set the size by which the memory grows - round up to the next power of 2 +//----------------------------------------------------------------------------- +template< class T, class I > +void CUtlBlockMemory::Init( int nGrowSize /* = 0 */, int nInitSize /* = 0 */ ) +{ + Purge(); + + if ( nGrowSize == 0) + { + // default grow size is smallest size s.t. c++ allocation overhead is ~6% of block size + nGrowSize = ( 127 + sizeof( T ) ) / sizeof( T ); + } + nGrowSize = SmallestPowerOfTwoGreaterOrEqual( nGrowSize ); + m_nIndexMask = nGrowSize - 1; + + m_nIndexShift = 0; + while ( nGrowSize > 1 ) + { + nGrowSize >>= 1; + ++m_nIndexShift; + } + Assert( m_nIndexMask + 1 == ( 1 << m_nIndexShift ) ); + + Grow( nInitSize ); +} + + +//----------------------------------------------------------------------------- +// element access +//----------------------------------------------------------------------------- +template< class T, class I > +inline T& CUtlBlockMemory::operator[]( I i ) +{ + Assert( IsIdxValid(i) ); + T *pBlock = m_pMemory[ MajorIndex( i ) ]; + return pBlock[ MinorIndex( i ) ]; +} + +template< class T, class I > +inline const T& CUtlBlockMemory::operator[]( I i ) const +{ + Assert( IsIdxValid(i) ); + const T *pBlock = m_pMemory[ MajorIndex( i ) ]; + return pBlock[ MinorIndex( i ) ]; +} + +template< class T, class I > +inline T& CUtlBlockMemory::Element( I i ) +{ + Assert( IsIdxValid(i) ); + T *pBlock = m_pMemory[ MajorIndex( i ) ]; + return pBlock[ MinorIndex( i ) ]; +} + +template< class T, class I > +inline const T& CUtlBlockMemory::Element( I i ) const +{ + Assert( IsIdxValid(i) ); + const T *pBlock = m_pMemory[ MajorIndex( i ) ]; + return pBlock[ MinorIndex( i ) ]; +} + + +//----------------------------------------------------------------------------- +// Size +//----------------------------------------------------------------------------- +template< class T, class I > +inline int CUtlBlockMemory::NumAllocated() const +{ + return m_nBlocks * NumElementsInBlock(); +} + + +//----------------------------------------------------------------------------- +// Is element index valid? +//----------------------------------------------------------------------------- +template< class T, class I > +inline bool CUtlBlockMemory::IsIdxValid( I i ) const +{ + return ( i >= 0 ) && ( MajorIndex( i ) < m_nBlocks ); +} + +template< class T, class I > +void CUtlBlockMemory::Grow( int num ) +{ + if ( num <= 0 ) + return; + + int nBlockSize = NumElementsInBlock(); + int nBlocks = ( num + nBlockSize - 1 ) / nBlockSize; + + ChangeSize( m_nBlocks + nBlocks ); +} + +template< class T, class I > +void CUtlBlockMemory::ChangeSize( int nBlocks ) +{ + UTLBLOCKMEMORY_TRACK_FREE(); // this must stay before the recalculation of m_nBlocks, since it implicitly uses the old value + + int nBlocksOld = m_nBlocks; + m_nBlocks = nBlocks; + + UTLBLOCKMEMORY_TRACK_ALLOC(); // this must stay after the recalculation of m_nBlocks, since it implicitly uses the new value + + // free old blocks if shrinking + for ( int i = m_nBlocks; i < nBlocksOld; ++i ) + { + UTLBLOCKMEMORY_TRACK_FREE(); + free( (void*)m_pMemory[ i ] ); + } + + if ( m_pMemory ) + { + MEM_ALLOC_CREDIT_CLASS(); + m_pMemory = (T**)realloc( m_pMemory, m_nBlocks * sizeof(T*) ); + Assert( m_pMemory ); + } + else + { + MEM_ALLOC_CREDIT_CLASS(); + m_pMemory = (T**)malloc( m_nBlocks * sizeof(T*) ); + Assert( m_pMemory ); + } + + if ( !m_pMemory ) + { + //Error( "CUtlBlockMemory overflow!\n" ); + __debugbreak(); + } + + // allocate new blocks if growing + int nBlockSize = NumElementsInBlock(); + for ( int i = nBlocksOld; i < m_nBlocks; ++i ) + { + MEM_ALLOC_CREDIT_CLASS(); + m_pMemory[ i ] = (T*)malloc( nBlockSize * sizeof( T ) ); + Assert( m_pMemory[ i ] ); + } +} + + +//----------------------------------------------------------------------------- +// Makes sure we've got at least this much memory +//----------------------------------------------------------------------------- +template< class T, class I > +inline void CUtlBlockMemory::EnsureCapacity( int num ) +{ + Grow( num - NumAllocated() ); +} + + +//----------------------------------------------------------------------------- +// Memory deallocation +//----------------------------------------------------------------------------- +template< class T, class I > +void CUtlBlockMemory::Purge() +{ + if ( !m_pMemory ) + return; + + for ( int i = 0; i < m_nBlocks; ++i ) + { + UTLBLOCKMEMORY_TRACK_FREE(); + free( (void*)m_pMemory[ i ] ); + } + m_nBlocks = 0; + + UTLBLOCKMEMORY_TRACK_FREE(); + free( (void*)m_pMemory ); + m_pMemory = 0; +} + +template< class T, class I > +void CUtlBlockMemory::Purge( int numElements ) +{ + Assert( numElements >= 0 ); + + int nAllocated = NumAllocated(); + if ( numElements > nAllocated ) + { + // Ensure this isn't a grow request in disguise. + Assert( numElements <= nAllocated ); + return; + } + + if ( numElements <= 0 ) + { + Purge(); + return; + } + + int nBlockSize = NumElementsInBlock(); + // int nBlocksOld = m_nBlocks; + int nBlocks = ( numElements + nBlockSize - 1 ) / nBlockSize; + + // If the number of blocks is the same as the allocated number of blocks, we are done. + if ( nBlocks == m_nBlocks ) + return; + + ChangeSize( nBlocks ); +} + + +#endif // UTLBLOCKMEMORY_H diff --git a/csgo2/sdk/tier1/utlfixedmemory.h b/csgo2/sdk/tier1/utlfixedmemory.h new file mode 100644 index 0000000..390b2c8 --- /dev/null +++ b/csgo2/sdk/tier1/utlfixedmemory.h @@ -0,0 +1,337 @@ +//===== Copyright � 1996-2005, Valve Corporation, All rights reserved. ======// +// +// Purpose: +// +// $NoKeywords: $ +// +// A growable memory class. +//===========================================================================// +#ifndef UTLFIXEDMEMORY_H +#define UTLFIXEDMEMORY_H + +#ifdef _WIN32 +#pragma once +#endif +#include "../sdk.h" +#ifdef _MSC_VER +#pragma warning (disable:4100) +#pragma warning (disable:4514) +#endif + +//----------------------------------------------------------------------------- + +#ifdef UTLFIXEDMEMORY_TRACK +#define UTLFIXEDMEMORY_TRACK_ALLOC() MemAlloc_RegisterAllocation( "Sum of all UtlFixedMemory", 0, NumAllocated() * sizeof(T), NumAllocated() * sizeof(T), 0 ) +#define UTLFIXEDMEMORY_TRACK_FREE() if ( !m_pMemory ) ; else MemAlloc_RegisterDeallocation( "Sum of all UtlFixedMemory", 0, NumAllocated() * sizeof(T), NumAllocated() * sizeof(T), 0 ) +#else +#define UTLFIXEDMEMORY_TRACK_ALLOC() ((void)0) +#define UTLFIXEDMEMORY_TRACK_FREE() ((void)0) +#endif + + +//----------------------------------------------------------------------------- +// The CUtlFixedMemory class: +// A growable memory class that allocates non-sequential blocks, but is indexed sequentially +//----------------------------------------------------------------------------- +template< class T > +class CUtlFixedMemory +{ +public: + // constructor, destructor + CUtlFixedMemory( int nGrowSize = 0, int nInitSize = 0 ); + ~CUtlFixedMemory(); + + // Set the size by which the memory grows + void Init( int nGrowSize = 0, int nInitSize = 0 ); + + // here to match CUtlMemory, but not used, so it can just return NULL + T* Base() { return NULL; } + const T* Base() const { return NULL; } + +protected: + struct BlockHeader_t; + +public: + class Iterator_t + { + public: + Iterator_t( BlockHeader_t *p, int i ) : m_pBlockHeader( p ), m_nIndex( i ) {} + BlockHeader_t *m_pBlockHeader; + intp m_nIndex; + + bool operator==( const Iterator_t it ) const { return m_pBlockHeader == it.m_pBlockHeader && m_nIndex == it.m_nIndex; } + bool operator!=( const Iterator_t it ) const { return m_pBlockHeader != it.m_pBlockHeader || m_nIndex != it.m_nIndex; } + }; + Iterator_t First() const { return m_pBlocks ? Iterator_t( m_pBlocks, 0 ) : InvalidIterator(); } + Iterator_t Next( const Iterator_t &it ) const + { + if ( !IsValidIterator( it ) ) + return InvalidIterator(); + + BlockHeader_t * RESTRICT pHeader = it.m_pBlockHeader; + if ( it.m_nIndex + 1 < pHeader->m_nBlockSize ) + return Iterator_t( pHeader, it.m_nIndex + 1 ); + + return pHeader->m_pNext ? Iterator_t( pHeader->m_pNext, 0 ) : InvalidIterator(); + } + intp GetIndex( const Iterator_t &it ) const + { + if ( !IsValidIterator( it ) ) + return InvalidIndex(); + + return ( intp )( HeaderToBlock( it.m_pBlockHeader ) + it.m_nIndex ); + } + bool IsIdxAfter( intp i, const Iterator_t &it ) const + { + if ( !IsValidIterator( it ) ) + return false; + + if ( IsInBlock( i, it.m_pBlockHeader ) ) + return i > GetIndex( it ); + + for ( BlockHeader_t * RESTRICT pbh = it.m_pBlockHeader->m_pNext; pbh; pbh = pbh->m_pNext ) + { + if ( IsInBlock( i, pbh ) ) + return true; + } + return false; + } + bool IsValidIterator( const Iterator_t &it ) const { return it.m_pBlockHeader && it.m_nIndex >= 0 && it.m_nIndex < it.m_pBlockHeader->m_nBlockSize; } + Iterator_t InvalidIterator() const { return Iterator_t( NULL, INVALID_INDEX ); } + + // element access + T& operator[]( intp i ); + const T& operator[]( intp i ) const; + T& Element( intp i ); + const T& Element( intp i ) const; + + // Can we use this index? + bool IsIdxValid( intp i ) const; + + // Specify the invalid ('null') index that we'll only return on failure + static const intp INVALID_INDEX = 0; // For use with COMPILE_TIME_ASSERT + static intp InvalidIndex() { return INVALID_INDEX; } + + // Size + int NumAllocated() const; + int Count() const { return NumAllocated(); } + + // Grows memory by max(num,growsize), and returns the allocation index/ptr + void Grow( int num = 1 ); + + // Makes sure we've got at least this much memory + void EnsureCapacity( int num ); + + // Memory deallocation + void Purge(); + +protected: + // Fast swap - WARNING: Swap invalidates all ptr-based indices!!! + void Swap( CUtlFixedMemory< T > &mem ); + + bool IsInBlock( intp i, BlockHeader_t *pBlockHeader ) const + { + T *p = ( T* )i; + const T *p0 = HeaderToBlock( pBlockHeader ); + return p >= p0 && p < p0 + pBlockHeader->m_nBlockSize; + } + + struct BlockHeader_t + { + BlockHeader_t *m_pNext; + intp m_nBlockSize; + }; + + const T *HeaderToBlock( const BlockHeader_t *pHeader ) const { return ( T* )( pHeader + 1 ); } + const BlockHeader_t *BlockToHeader( const T *pBlock ) const { return ( BlockHeader_t* )( pBlock ) - 1; } + + BlockHeader_t* m_pBlocks; + int m_nAllocationCount; + int m_nGrowSize; +}; + +//----------------------------------------------------------------------------- +// constructor, destructor +//----------------------------------------------------------------------------- + +template< class T > +CUtlFixedMemory::CUtlFixedMemory( int nGrowSize, int nInitAllocationCount ) +: m_pBlocks( 0 ), m_nAllocationCount( 0 ), m_nGrowSize( 0 ) +{ + Init( nGrowSize, nInitAllocationCount ); +} + +template< class T > +CUtlFixedMemory::~CUtlFixedMemory() +{ + Purge(); +} + + +//----------------------------------------------------------------------------- +// Fast swap - WARNING: Swap invalidates all ptr-based indices!!! +//----------------------------------------------------------------------------- +template< class T > +void CUtlFixedMemory::Swap( CUtlFixedMemory< T > &mem ) +{ + V_swap( m_pBlocks, mem.m_pBlocks ); + V_swap( m_nAllocationCount, mem.m_nAllocationCount ); + V_swap( m_nGrowSize, mem.m_nGrowSize ); +} + + +//----------------------------------------------------------------------------- +// Set the size by which the memory grows - round up to the next power of 2 +//----------------------------------------------------------------------------- +template< class T > +void CUtlFixedMemory::Init( int nGrowSize /* = 0 */, int nInitSize /* = 0 */ ) +{ + Purge(); + + m_nGrowSize = nGrowSize; + + Grow( nInitSize ); +} + +//----------------------------------------------------------------------------- +// element access +//----------------------------------------------------------------------------- +template< class T > +inline T& CUtlFixedMemory::operator[]( intp i ) +{ + return *( T* )i; +} + +template< class T > +inline const T& CUtlFixedMemory::operator[]( intp i ) const +{ + return *( T* )i; +} + +template< class T > +inline T& CUtlFixedMemory::Element( intp i ) +{ + return *( T* )i; +} + +template< class T > +inline const T& CUtlFixedMemory::Element( intp i ) const +{ + return *( T* )i; +} + + +//----------------------------------------------------------------------------- +// Size +//----------------------------------------------------------------------------- +template< class T > +inline int CUtlFixedMemory::NumAllocated() const +{ + return m_nAllocationCount; +} + + +//----------------------------------------------------------------------------- +// Is element index valid? +//----------------------------------------------------------------------------- +template< class T > +inline bool CUtlFixedMemory::IsIdxValid( intp i ) const +{ +#ifdef _DEBUG + for ( BlockHeader_t *pbh = m_pBlocks; pbh; pbh = pbh->m_pNext ) + { + if ( IsInBlock( i, pbh ) ) + return true; + } + return false; +#else + return i != InvalidIndex(); +#endif +} + +template< class T > +void CUtlFixedMemory::Grow( int num ) +{ + if ( num <= 0 ) + return; + + int nBlockSize = m_nGrowSize; + if ( nBlockSize == 0 ) + { + if ( m_nAllocationCount ) + { + nBlockSize = m_nAllocationCount; + } + else + { + // Compute an allocation which is at least as big as a cache line... + nBlockSize = ( 31 + sizeof( T ) ) / sizeof( T ); + } + } + if ( nBlockSize < num ) + { + int n = ( num + nBlockSize -1 ) / nBlockSize; + nBlockSize *= n; + } + m_nAllocationCount += nBlockSize; + + MEM_ALLOC_CREDIT_CLASS(); + BlockHeader_t * RESTRICT pBlockHeader = ( BlockHeader_t* )malloc( sizeof( BlockHeader_t ) + nBlockSize * sizeof( T ) ); + if ( !pBlockHeader ) + { + __debugbreak(); + } + pBlockHeader->m_pNext = NULL; + pBlockHeader->m_nBlockSize = nBlockSize; + + if ( !m_pBlocks ) + { + m_pBlocks = pBlockHeader; + } + else + { +#if 1 // IsIdxAfter assumes that newly allocated blocks are at the end + BlockHeader_t * RESTRICT pbh = m_pBlocks; + while ( pbh->m_pNext ) + { + pbh = pbh->m_pNext; + } + pbh->m_pNext = pBlockHeader; +#else + pBlockHeader = m_pBlocks; + pBlockHeader->m_pNext = m_pBlocks; +#endif + } +} + + +//----------------------------------------------------------------------------- +// Makes sure we've got at least this much memory +//----------------------------------------------------------------------------- +template< class T > +inline void CUtlFixedMemory::EnsureCapacity( int num ) +{ + Grow( num - NumAllocated() ); +} + + +//----------------------------------------------------------------------------- +// Memory deallocation +//----------------------------------------------------------------------------- +template< class T > +void CUtlFixedMemory::Purge() +{ + if ( !m_pBlocks ) + return; + + for ( BlockHeader_t *pbh = m_pBlocks; pbh; ) + { + BlockHeader_t *pFree = pbh; + pbh = pbh->m_pNext; + free( pFree ); + } + m_pBlocks = NULL; + m_nAllocationCount = 0; +} + +#endif // UTLFIXEDMEMORY_H diff --git a/csgo2/vector.h b/csgo2/vector.h new file mode 100644 index 0000000..ae736d0 --- /dev/null +++ b/csgo2/vector.h @@ -0,0 +1,404 @@ +#pragma once +#include "head.h" +#define pi 3.14159265358979323846 +#define deg(a) a*(180/pi) +#define CHECK_VALID( _v ) 0 + +class Vector +{ +public: + float x, y, z; + Vector(void); + Vector(float X, float Y, float Z); + void Init(float ix = 0.0f, float iy = 0.0f, float iz = 0.0f); + bool IsValid() const; + float operator[](int i) const; + float& operator[](int i); + inline void Zero(); + bool operator==(const Vector& v) const; + bool operator!=(const Vector& v) const; + __forceinline Vector& operator+=(const Vector& v); + __forceinline Vector& operator-=(const Vector& v); + __forceinline Vector& operator*=(const Vector& v); + __forceinline Vector& operator*=(float s); + __forceinline Vector& operator/=(const Vector& v); + Vector Angle(Vector* up); + __forceinline Vector& operator/=(float s); + __forceinline Vector& operator+=(float fl); + __forceinline Vector& operator-=(float fl); + inline float Length() const; + inline Vector Cross(Vector a) { return Vector(y * a.z - z * a.y, z * a.x - x * a.z, x * a.y - y * a.x); } + + __forceinline float LengthSqr(void) const + { + CHECK_VALID(*this); + return (this->x * this->x + this->y * this->y + this->z * this->z); + } + + bool IsZero(float tolerance = 0.01f) const + { + return (x > -tolerance && x < tolerance&& + y > -tolerance && y < tolerance&& + z > -tolerance && z < tolerance); + } + + float NormalizeInPlace(); + Vector Normalize(); + __forceinline float DistToSqr(const Vector& vOther) const; + __forceinline float Dist(const Vector& vOther) const; + float Dot(const Vector& vOther) const; + float Dot(const float* fOther) const; + float Length2D(void) const; + float Length2DSqr(void) const; + Vector& operator=(const Vector& vOther); + Vector operator-(const Vector& v) const; + Vector operator+(const Vector& v) const; + Vector operator*(const Vector& v) const; + Vector operator/(const Vector& v) const; + Vector operator*(float fl) const; + Vector operator/(float fl) const; + // Base address... + float* Base(); + float const* Base() const; +}; + +//=============================================== +inline void Vector::Init(float ix, float iy, float iz) +{ + x = ix; + y = iy; + z = iz; + CHECK_VALID(*this); +} + +inline bool Vector::IsValid() const +{ + return x == 0.f && y == 0.f && z == 0.f; +} + +//=============================================== +inline Vector::Vector(float X, float Y, float Z) +{ + x = X; + y = Y; + z = Z; + CHECK_VALID(*this); +} + +//=============================================== +inline Vector::Vector(void) +{ } + +//=============================================== +inline void Vector::Zero() +{ + x = y = z = 0.0f; +} + +//=============================================== +inline void VectorClear(Vector& a) +{ + a.x = a.y = a.z = 0.0f; +} + +//=============================================== +inline Vector& Vector::operator=(const Vector& vOther) +{ + CHECK_VALID(vOther); + x = vOther.x; + y = vOther.y; + z = vOther.z; + return *this; +} + +//=============================================== +inline float& Vector::operator[](int i) +{ + return ((float*)this)[i]; +} + +//=============================================== +inline float Vector::operator[](int i) const +{ + return ((float*)this)[i]; +} + +//=============================================== +inline bool Vector::operator==(const Vector& src) const +{ + CHECK_VALID(src); + CHECK_VALID(*this); + return (src.x == x) && (src.y == y) && (src.z == z); +} + +//=============================================== +inline bool Vector::operator!=(const Vector& src) const +{ + CHECK_VALID(src); + CHECK_VALID(*this); + return (src.x != x) || (src.y != y) || (src.z != z); +} + +//=============================================== +__forceinline void VectorCopy(const Vector& src, Vector& dst) +{ + CHECK_VALID(src); + dst.x = src.x; + dst.y = src.y; + dst.z = src.z; +} + +//=============================================== +__forceinline Vector& Vector::operator+=(const Vector& v) +{ + CHECK_VALID(*this); + CHECK_VALID(v); + x += v.x; + y += v.y; + z += v.z; + return *this; +} + +//=============================================== +__forceinline Vector& Vector::operator-=(const Vector& v) +{ + CHECK_VALID(*this); + CHECK_VALID(v); + x -= v.x; + y -= v.y; + z -= v.z; + return *this; +} + +//=============================================== +__forceinline Vector& Vector::operator*=(float fl) +{ + x *= fl; + y *= fl; + z *= fl; + CHECK_VALID(*this); + return *this; +} + +//=============================================== +__forceinline Vector& Vector::operator*=(const Vector& v) +{ + CHECK_VALID(v); + x *= v.x; + y *= v.y; + z *= v.z; + CHECK_VALID(*this); + return *this; +} + +//=============================================== +__forceinline Vector& Vector::operator+=(float fl) +{ + x += fl; + y += fl; + z += fl; + CHECK_VALID(*this); + return *this; +} + +//=============================================== +__forceinline Vector& Vector::operator-=(float fl) +{ + x -= fl; + y -= fl; + z -= fl; + CHECK_VALID(*this); + return *this; +} + +//=============================================== +__forceinline Vector& Vector::operator/=(float fl) +{ + float oofl = 1.0f / fl; + x *= oofl; + y *= oofl; + z *= oofl; + CHECK_VALID(*this); + return *this; +} + +//=============================================== +__forceinline Vector& Vector::operator/=(const Vector& v) +{ + CHECK_VALID(v); + x /= v.x; + y /= v.y; + z /= v.z; + CHECK_VALID(*this); + return *this; +} +//=============================================== +inline float Vector::Length2DSqr(void) const +{ + return (x * x + y * y); +} + +//=============================================== +inline Vector CrossProduct(const Vector& a, const Vector& b) +{ + return Vector(a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x); +} + +//=============================================== +float Vector::DistToSqr(const Vector& vOther) const +{ + Vector delta; + + delta.x = x - vOther.x; + delta.y = y - vOther.y; + delta.z = z - vOther.z; + + return delta.LengthSqr(); +} + +float Vector::Dist(const Vector& vOther) const +{ + Vector delta; + + delta.x = x - vOther.x; + delta.y = y - vOther.y; + delta.z = z - vOther.z; + + return delta.Length(); +} + +inline Vector Vector::Normalize() +{ + Vector vector; + float length = this->Length(); + + if (length != 0) + { + vector.x = x / length; + vector.y = y / length; + vector.z = z / length; + } + else + vector.x = vector.y = 0.0f; + vector.z = 1.0f; + + return vector; +} + +//=============================================== +inline float Vector::NormalizeInPlace() +{ + Vector& v = *this; + + float iradius = 1.f / (this->Length() + 1.192092896e-07F); //FLT_EPSILON + + v.x *= iradius; + v.y *= iradius; + v.z *= iradius; +} + +//=============================================== +inline float VectorNormalize(Vector& v) +{ + float l = v.Length(); + if (l != 0.0f) + { + v /= l; + } + else + { + v.x = v.y = 0.0f; + v.z = 1.0f; + } + return l; +} + +//=============================================== +FORCEINLINE float VectorNormalize(float* v) +{ + return VectorNormalize(*(reinterpret_cast(v))); +} + +//=============================================== +inline Vector Vector::operator+(const Vector& v) const +{ + Vector res; + res.x = x + v.x; + res.y = y + v.y; + res.z = z + v.z; + return res; +} + +//=============================================== +inline Vector Vector::operator-(const Vector& v) const +{ + Vector res; + res.x = x - v.x; + res.y = y - v.y; + res.z = z - v.z; + return res; +} + +//=============================================== +inline Vector Vector::operator*(float fl) const +{ + Vector res; + res.x = x * fl; + res.y = y * fl; + res.z = z * fl; + return res; +} + +//=============================================== +inline Vector Vector::operator*(const Vector& v) const +{ + Vector res; + res.x = x * v.x; + res.y = y * v.y; + res.z = z * v.z; + return res; +} + +//=============================================== +inline Vector Vector::operator/(float fl) const +{ + Vector res; + res.x = x / fl; + res.y = y / fl; + res.z = z / fl; + return res; +} + +//=============================================== +inline Vector Vector::operator/(const Vector& v) const +{ + Vector res; + res.x = x / v.x; + res.y = y / v.y; + res.z = z / v.z; + return res; +} + +inline float Vector::Dot(const Vector& vOther) const +{ + const Vector& a = *this; + + return (a.x * vOther.x + a.y * vOther.y + a.z * vOther.z); +} + +inline float Vector::Dot(const float* fOther) const +{ + const Vector& a = *this; + + return (a.x * fOther[0] + a.y * fOther[1] + a.z * fOther[2]); +} + +inline float* Vector::Base() +{ + return (float*)this; +} + +inline float const* Vector::Base() const +{ + return (float const*)this; +} \ No newline at end of file