This commit is contained in:
Huoji's
2023-10-03 04:07:50 +08:00
parent f08e0b90fa
commit 8f3005e9b2
50 changed files with 11966 additions and 107 deletions

View File

@@ -0,0 +1,62 @@
// https://github.com/vinniefalco/LuaBridge
//
// Copyright 2020, Dmitry Tarakanov
// SPDX-License-Identifier: MIT
#pragma once
#include <LuaBridge/detail/Stack.h>
#include <array>
namespace luabridge {
template<class T, std::size_t s>
struct Stack<std::array<T, s>>
{
static void push(lua_State* L, std::array<T, s> const& array)
{
lua_createtable(L, static_cast<int>(s), 0);
for (std::size_t i = 0; i < s; ++i)
{
lua_pushinteger(L, static_cast<lua_Integer>(i + 1));
Stack<T>::push(L, array[i]);
lua_settable(L, -3);
}
}
static std::array<T, s> 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<std::size_t>(get_length(L, index));
if (tableSize != s)
{
luaL_error(L, "array size must be %d ", s);
}
std::array<T, s> array;
int const absindex = lua_absindex(L, index);
lua_pushnil(L);
int arrayIndex = 0;
while (lua_next(L, absindex) != 0)
{
array[arrayIndex] = Stack<T>::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

View File

@@ -0,0 +1,51 @@
// https://github.com/vinniefalco/LuaBridge
// Copyright 2020, Dmitry Tarakanov
// SPDX-License-Identifier: MIT
#pragma once
#include <LuaBridge/detail/Stack.h>
#include <list>
namespace luabridge {
template<class T>
struct Stack<std::list<T>>
{
static void push(lua_State* L, std::list<T> const& list)
{
lua_createtable(L, static_cast<int>(list.size()), 0);
typename std::list<T>::const_iterator item = list.begin();
for (std::size_t i = 1; i <= list.size(); ++i)
{
lua_pushinteger(L, static_cast<lua_Integer>(i));
Stack<T>::push(L, *item);
lua_settable(L, -3);
++item;
}
}
static std::list<T> get(lua_State* L, int index)
{
if (!lua_istable(L, index))
{
luaL_error(L, "#%d argument must be a table", index);
}
std::list<T> list;
int const absindex = lua_absindex(L, index);
lua_pushnil(L);
while (lua_next(L, absindex) != 0)
{
list.push_back(Stack<T>::get(L, -1));
lua_pop(L, 1);
}
return list;
}
static bool isInstance(lua_State* L, int index) { return lua_istable(L, index); }
};
} // namespace luabridge

View File

@@ -0,0 +1,34 @@
// https://github.com/vinniefalco/LuaBridge
// Copyright 2020, Dmitry Tarakanov
// Copyright 2012, Vinnie Falco <vinnie.falco@gmail.com>
// 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 <LuaBridge/detail/CFunctions.h>
#include <LuaBridge/detail/ClassInfo.h>
#include <LuaBridge/detail/Constructor.h>
#include <LuaBridge/detail/FuncTraits.h>
#include <LuaBridge/detail/Iterator.h>
#include <LuaBridge/detail/LuaException.h>
#include <LuaBridge/detail/LuaHelpers.h>
#include <LuaBridge/detail/LuaRef.h>
#include <LuaBridge/detail/Namespace.h>
#include <LuaBridge/detail/Security.h>
#include <LuaBridge/detail/Stack.h>
#include <LuaBridge/detail/TypeList.h>
#include <LuaBridge/detail/TypeTraits.h>
#include <LuaBridge/detail/Userdata.h>

View File

@@ -0,0 +1,52 @@
// https://github.com/vinniefalco/LuaBridge
// Copyright 2018, Dmitry Tarakanov
// SPDX-License-Identifier: MIT
#pragma once
#include <LuaBridge/detail/Stack.h>
#include <LuaBridge/detail/dump.h>
#include <map>
namespace luabridge {
template<class K, class V>
struct Stack<std::map<K, V>>
{
typedef std::map<K, V> Map;
static void push(lua_State* L, const Map& map)
{
lua_createtable(L, 0, static_cast<int>(map.size()));
typedef typename Map::const_iterator ConstIter;
for (ConstIter i = map.begin(); i != map.end(); ++i)
{
Stack<K>::push(L, i->first);
Stack<V>::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<K>::get(L, -2), Stack<V>::get(L, -1));
lua_pop(L, 1);
}
return map;
}
static bool isInstance(lua_State* L, int index) { return lua_istable(L, index); }
};
} // namespace luabridge

View File

@@ -0,0 +1,46 @@
// https://github.com/vinniefalco/LuaBridge
// Copyright 2021, Stefan Frings
// SPDX-License-Identifier: MIT
#pragma once
#include <LuaBridge/detail/Stack.h>
#include <optional>
namespace luabridge {
template<class T>
struct Stack<std::optional<T>>
{
static void push(lua_State* L, std::optional<T> const& optional)
{
if (optional)
{
Stack<T>::push(L, *optional);
}
else
{
lua_pushnil(L);
}
}
static std::optional<T> get(lua_State* L, int index)
{
if (lua_isnil(L, index))
{
lua_pop(L, 1);
return std::nullopt;
}
return Stack<T>::get(L, index);
}
static bool isInstance(lua_State* L, int index)
{
return lua_isnil(L, index) || Stack<T>::isInstance(L, index);
}
};
} // namespace luabridge

View File

@@ -0,0 +1,77 @@
// https://github.com/vinniefalco/LuaBridge
// Copyright 2022, Stefan Frings
// SPDX-License-Identifier: MIT
#pragma once
#include <LuaBridge/detail/Stack.h>
#include <cassert>
#include <utility>
namespace luabridge {
template<class T1, class T2>
struct Stack<std::pair<T1, T2>>
{
static void push(lua_State* L, std::pair<T1, T2> const& pair)
{
lua_createtable(L, 2, 0);
lua_pushinteger(L, static_cast<lua_Integer>(1));
Stack<T1>::push(L, pair.first);
lua_settable(L, -3);
lua_pushinteger(L, static_cast<lua_Integer>(2));
Stack<T2>::push(L, pair.second);
lua_settable(L, -3);
}
static std::pair<T1, T2> 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<std::size_t>(get_length(L, index));
if (tableSize != 2)
{
luaL_error(L, "pair size must be 2");
}
std::pair<T1, T2> pair;
int const absindex = lua_absindex(L, index);
lua_pushnil(L);
{
int const next = lua_next(L, absindex);
assert(next != 0);
pair.first = Stack<T1>::get(L, -1);
lua_pop(L, 1);
}
{
int const next = lua_next(L, absindex);
assert(next != 0);
pair.second = Stack<T2>::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

View File

@@ -0,0 +1,317 @@
// https://github.com/vinniefalco/LuaBridge
// Copyright 2012, Vinnie Falco <vinnie.falco@gmail.com>
// 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 <cassert>
#include <utility>
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<MyClass> 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 CounterType>
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<int>(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<int> 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 <MyClass> MyClassPtr;
@endcode
*/
template<class ReferenceCountedObjectClass>
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<class DerivedClass>
RefCountedObjectPtr(const RefCountedObjectPtr<DerivedClass>& other)
: referencedObject(static_cast<ReferenceCountedObjectClass*>(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<class DerivedClass>
RefCountedObjectPtr& operator=(const RefCountedObjectPtr<DerivedClass>& other)
{
return operator=(static_cast<ReferenceCountedObjectClass*>(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<class T>
struct ContainerTraits;
template<class T>
struct ContainerTraits<RefCountedObjectPtr<T>>
{
typedef T Type;
static T* get(RefCountedObjectPtr<T> const& c) { return c.getObject(); }
};
//==============================================================================
} // namespace luabridge

View File

@@ -0,0 +1,226 @@
// https://github.com/vinniefalco/LuaBridge
// Copyright 2021, Stefan Frings
// Copyright 2019, Dmitry Tarakanov
// Copyright 2012, Vinnie Falco <vinnie.falco@gmail.com>
// Copyright 2007, Nathan Reed
// SPDX-License-Identifier: MIT
#pragma once
#include <cassert>
#include <unordered_map>
#include <utility>
namespace luabridge {
namespace detail {
//==============================================================================
/**
Support for our RefCountedPtr.
*/
struct RefCountedPtrBase
{
// Declaration of container for the refcounts
typedef std::unordered_map<const void*, int> 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 T>
class RefCountedPtr : private detail::RefCountedPtrBase
{
public:
template<typename Other>
struct rebind
{
typedef RefCountedPtr<Other> 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<T> 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<typename U>
RefCountedPtr(RefCountedPtr<U> 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<T>& operator=(RefCountedPtr<T> 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<typename U>
RefCountedPtr<T>& operator=(RefCountedPtr<U> const& rhs)
{
// NOTE Self assignment is handled gracefully
*this = rhs.get();
return *this;
}
RefCountedPtr<T>& operator=(T* const p)
{
if (p != m_p)
{
RefCountedPtr<T> 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<class T>
struct ContainerTraits;
template<class T>
struct ContainerTraits<RefCountedPtr<T>>
{
typedef T Type;
static T* get(RefCountedPtr<T> const& c) { return c.get(); }
};
} // namespace luabridge

View File

@@ -0,0 +1,51 @@
// https://github.com/vinniefalco/LuaBridge
// Copyright 2019, Dmitry Tarakanov
// SPDX-License-Identifier: MIT
#pragma once
#include <LuaBridge/detail/Stack.h>
#include <unordered_map>
namespace luabridge {
template<class K, class V>
struct Stack<std::unordered_map<K, V>>
{
typedef std::unordered_map<K, V> Map;
static void push(lua_State* L, const Map& map)
{
lua_createtable(L, 0, static_cast<int>(map.size()));
typedef typename Map::const_iterator ConstIter;
for (ConstIter i = map.begin(); i != map.end(); ++i)
{
Stack<K>::push(L, i->first);
Stack<V>::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<K>::get(L, -2), Stack<V>::get(L, -1));
lua_pop(L, 1);
}
return map;
}
static bool isInstance(lua_State* L, int index) { return lua_istable(L, index); }
};
} // namespace luabridge

View File

@@ -0,0 +1,50 @@
// https://github.com/vinniefalco/LuaBridge
// Copyright 2018, Dmitry Tarakanov
// SPDX-License-Identifier: MIT
#pragma once
#include <LuaBridge/detail/Stack.h>
#include <vector>
namespace luabridge {
template<class T>
struct Stack<std::vector<T>>
{
static void push(lua_State* L, std::vector<T> const& vector)
{
lua_createtable(L, static_cast<int>(vector.size()), 0);
for (std::size_t i = 0; i < vector.size(); ++i)
{
lua_pushinteger(L, static_cast<lua_Integer>(i + 1));
Stack<T>::push(L, vector[i]);
lua_settable(L, -3);
}
}
static std::vector<T> get(lua_State* L, int index)
{
if (!lua_istable(L, index))
{
luaL_error(L, "#%d argument must be a table", index);
}
std::vector<T> vector;
vector.reserve(static_cast<std::size_t>(get_length(L, index)));
int const absindex = lua_absindex(L, index);
lua_pushnil(L);
while (lua_next(L, absindex) != 0)
{
vector.push_back(Stack<T>::get(L, -1));
lua_pop(L, 1);
}
return vector;
}
static bool isInstance(lua_State* L, int index) { return lua_istable(L, index); }
};
} // namespace luabridge

View File

@@ -0,0 +1,470 @@
// https://github.com/vinniefalco/LuaBridge
// Copyright 2019, Dmitry Tarakanov
// Copyright 2012, Vinnie Falco <vinnie.falco@gmail.com>
// SPDX-License-Identifier: MIT
#pragma once
#include <LuaBridge/detail/Config.h>
#include <LuaBridge/detail/FuncTraits.h>
#include <string>
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<class T>
static int getVariable(lua_State* L)
{
assert(lua_islightuserdata(L, lua_upvalueindex(1)));
T const* ptr = static_cast<T const*>(lua_touserdata(L, lua_upvalueindex(1)));
assert(ptr != 0);
Stack<T>::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<class T>
static int setVariable(lua_State* L)
{
assert(lua_islightuserdata(L, lua_upvalueindex(1)));
T* ptr = static_cast<T*>(lua_touserdata(L, lua_upvalueindex(1)));
assert(ptr != 0);
*ptr = Stack<T>::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<class FnPtr>
struct Call
{
typedef typename FuncTraits<FnPtr>::Params Params;
typedef typename FuncTraits<FnPtr>::ReturnType ReturnType;
static int f(lua_State* L)
{
assert(lua_islightuserdata(L, lua_upvalueindex(1)));
FnPtr fnptr = reinterpret_cast<FnPtr>(lua_touserdata(L, lua_upvalueindex(1)));
assert(fnptr != 0);
return Invoke<ReturnType, Params, 1>::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<class MemFnPtr>
struct CallMember
{
typedef typename FuncTraits<MemFnPtr>::ClassType T;
typedef typename FuncTraits<MemFnPtr>::Params Params;
typedef typename FuncTraits<MemFnPtr>::ReturnType ReturnType;
static int f(lua_State* L)
{
assert(isfulluserdata(L, lua_upvalueindex(1)));
T* const t = Userdata::get<T>(L, 1, false);
MemFnPtr const& fnptr =
*static_cast<MemFnPtr const*>(lua_touserdata(L, lua_upvalueindex(1)));
assert(fnptr != 0);
return Invoke<ReturnType, Params, 2>::run(L, t, fnptr);
}
};
template<class MemFnPtr>
struct CallConstMember
{
typedef typename FuncTraits<MemFnPtr>::ClassType T;
typedef typename FuncTraits<MemFnPtr>::Params Params;
typedef typename FuncTraits<MemFnPtr>::ReturnType ReturnType;
static int f(lua_State* L)
{
assert(isfulluserdata(L, lua_upvalueindex(1)));
T const* const t = Userdata::get<T>(L, 1, true);
MemFnPtr const& fnptr =
*static_cast<MemFnPtr const*>(lua_touserdata(L, lua_upvalueindex(1)));
assert(fnptr != 0);
return Invoke<ReturnType, Params, 2>::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<class T>
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<T>(L, 1, false);
MFP const& fnptr = *static_cast<MFP const*>(lua_touserdata(L, lua_upvalueindex(1)));
assert(fnptr != 0);
return (t->*fnptr)(L);
}
};
template<class T>
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<T>(L, 1, true);
MFP const& fnptr = *static_cast<MFP const*>(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<class FnPtr>
struct CallProxyFunction
{
using Params = typename FuncTraits<FnPtr>::Params;
using ReturnType = typename FuncTraits<FnPtr>::ReturnType;
static int f(lua_State* L)
{
assert(lua_islightuserdata(L, lua_upvalueindex(1)));
auto fnptr = reinterpret_cast<FnPtr>(lua_touserdata(L, lua_upvalueindex(1)));
assert(fnptr != 0);
return Invoke<ReturnType, Params, 1>::run(L, fnptr);
}
};
template<class Functor>
struct CallProxyFunctor
{
using Params = typename FuncTraits<Functor>::Params;
using ReturnType = typename FuncTraits<Functor>::ReturnType;
static int f(lua_State* L)
{
assert(isfulluserdata(L, lua_upvalueindex(1)));
Functor& fn = *static_cast<Functor*>(lua_touserdata(L, lua_upvalueindex(1)));
return Invoke<ReturnType, Params, 1>::run(L, fn);
}
};
//--------------------------------------------------------------------------
// SFINAE Helpers
template<class MemFnPtr, bool isConst>
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<MemFnPtr>::f, 1);
lua_pushvalue(L, -1);
rawsetfield(L, -5, name); // const table
rawsetfield(L, -3, name); // class table
}
};
template<class MemFnPtr>
struct CallMemberFunctionHelper<MemFnPtr, false>
{
static void add(lua_State* L, char const* name, MemFnPtr mf)
{
new (lua_newuserdata(L, sizeof(MemFnPtr))) MemFnPtr(mf);
lua_pushcclosure(L, &CallMember<MemFnPtr>::f, 1);
rawsetfield(L, -3, name); // class table
}
};
//--------------------------------------------------------------------------
/**
__gc metamethod for a class.
*/
template<class C>
static int gcMetaMethod(lua_State* L)
{
Userdata* const ud = Userdata::getExact<C>(L, 1);
ud->~Userdata();
return 0;
}
/**
__gc metamethod for an arbitrary class.
*/
template<class T>
static int gcMetaMethodAny(lua_State* L)
{
assert(isfulluserdata(L, 1));
T* t = static_cast<T*>(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<class C, typename T>
static int getProperty(lua_State* L)
{
C* const c = Userdata::get<C>(L, 1, true);
T C::** mp = static_cast<T C::**>(lua_touserdata(L, lua_upvalueindex(1)));
try
{
Stack<T&>::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<class C, typename T>
static int setProperty(lua_State* L)
{
C* const c = Userdata::get<C>(L, 1, false);
T C::** mp = static_cast<T C::**>(lua_touserdata(L, lua_upvalueindex(1)));
try
{
c->** mp = Stack<T>::get(L, 2);
}
catch (const std::exception& e)
{
luaL_error(L, e.what());
}
return 0;
}
};
} // namespace detail
} // namespace luabridge

View File

@@ -0,0 +1,140 @@
// https://github.com/vinniefalco/LuaBridge
// Copyright 2020, Dmitry Tarakanov
// Copyright 2012, Vinnie Falco <vinnie.falco@gmail.com>
// 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<void*>(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<void*>(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<void*>(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<void*>(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<void*>(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<void*>(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<void*>(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<class T>
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<class T>
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<class T>
void const* getConstRegistryKey()
{
static char value;
return &value;
}
} // namespace detail
} // namespace luabridge

View File

@@ -0,0 +1,7 @@
// https://github.com/vinniefalco/LuaBridge
// Copyright 2020, Dmitry Tarakanov
// SPDX-License-Identifier: MIT
#pragma once
// Empty file

View File

@@ -0,0 +1,225 @@
// https://github.com/vinniefalco/LuaBridge
// Copyright 2012, Vinnie Falco <vinnie.falco@gmail.com>
// 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<class T, typename List>
struct Constructor
{
};
template<class T>
struct Constructor<T, None>
{
static T* call(TypeListValues<None> const&) { return new T; }
static T* call(void* mem, TypeListValues<None> const&) { return new (mem) T; }
};
template<class T, class P1>
struct Constructor<T, TypeList<P1>>
{
static T* call(const TypeListValues<TypeList<P1>>& tvl) { return new T(tvl.hd); }
static T* call(void* mem, const TypeListValues<TypeList<P1>>& tvl)
{
return new (mem) T(tvl.hd);
}
};
template<class T, class P1, class P2>
struct Constructor<T, TypeList<P1, TypeList<P2>>>
{
static T* call(const TypeListValues<TypeList<P1, TypeList<P2>>>& tvl)
{
return new T(tvl.hd, tvl.tl.hd);
}
static T* call(void* mem, const TypeListValues<TypeList<P1, TypeList<P2>>>& tvl)
{
return new (mem) T(tvl.hd, tvl.tl.hd);
}
};
template<class T, class P1, class P2, class P3>
struct Constructor<T, TypeList<P1, TypeList<P2, TypeList<P3>>>>
{
static T* call(const TypeListValues<TypeList<P1, TypeList<P2, TypeList<P3>>>>& tvl)
{
return new T(tvl.hd, tvl.tl.hd, tvl.tl.tl.hd);
}
static T* call(void* mem, const TypeListValues<TypeList<P1, TypeList<P2, TypeList<P3>>>>& tvl)
{
return new (mem) T(tvl.hd, tvl.tl.hd, tvl.tl.tl.hd);
}
};
template<class T, class P1, class P2, class P3, class P4>
struct Constructor<T, TypeList<P1, TypeList<P2, TypeList<P3, TypeList<P4>>>>>
{
static T*
call(const TypeListValues<TypeList<P1, TypeList<P2, TypeList<P3, TypeList<P4>>>>>& 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<TypeList<P1, TypeList<P2, TypeList<P3, TypeList<P4>>>>>& tvl)
{
return new (mem) T(tvl.hd, tvl.tl.hd, tvl.tl.tl.hd, tvl.tl.tl.tl.hd);
}
};
template<class T, class P1, class P2, class P3, class P4, class P5>
struct Constructor<T, TypeList<P1, TypeList<P2, TypeList<P3, TypeList<P4, TypeList<P5>>>>>>
{
static T*
call(const TypeListValues<TypeList<P1, TypeList<P2, TypeList<P3, TypeList<P4, TypeList<P5>>>>>>&
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<TypeList<P1, TypeList<P2, TypeList<P3, TypeList<P4, TypeList<P5>>>>>>&
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<class T, class P1, class P2, class P3, class P4, class P5, class P6>
struct Constructor<
T,
TypeList<P1, TypeList<P2, TypeList<P3, TypeList<P4, TypeList<P5, TypeList<P6>>>>>>>
{
static T*
call(const TypeListValues<
TypeList<P1, TypeList<P2, TypeList<P3, TypeList<P4, TypeList<P5, TypeList<P6>>>>>>>& 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<P1, TypeList<P2, TypeList<P3, TypeList<P4, TypeList<P5, TypeList<P6>>>>>>>&
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<class T, class P1, class P2, class P3, class P4, class P5, class P6, class P7>
struct Constructor<
T,
TypeList<P1,
TypeList<P2, TypeList<P3, TypeList<P4, TypeList<P5, TypeList<P6, TypeList<P7>>>>>>>>
{
static T*
call(const TypeListValues<TypeList<
P1,
TypeList<P2, TypeList<P3, TypeList<P4, TypeList<P5, TypeList<P6, TypeList<P7>>>>>>>>&
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<TypeList<
P1,
TypeList<P2, TypeList<P3, TypeList<P4, TypeList<P5, TypeList<P6, TypeList<P7>>>>>>>>&
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<class T, class P1, class P2, class P3, class P4, class P5, class P6, class P7, class P8>
struct Constructor<
T,
TypeList<
P1,
TypeList<
P2,
TypeList<P3, TypeList<P4, TypeList<P5, TypeList<P6, TypeList<P7, TypeList<P8>>>>>>>>>
{
static T*
call(const TypeListValues<TypeList<
P1,
TypeList<
P2,
TypeList<P3,
TypeList<P4, TypeList<P5, TypeList<P6, TypeList<P7, TypeList<P8>>>>>>>>>&
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<TypeList<
P1,
TypeList<
P2,
TypeList<P3,
TypeList<P4, TypeList<P5, TypeList<P6, TypeList<P7, TypeList<P8>>>>>>>>>&
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

View File

@@ -0,0 +1,435 @@
// https://github.com/vinniefalco/LuaBridge
// Copyright 2020, Dmitry Tarakanov
// Copyright 2012, Vinnie Falco <vinnie.falco@gmail.com>
// SPDX-License-Identifier: MIT
#pragma once
#include <LuaBridge/detail/Config.h>
#include <LuaBridge/detail/TypeList.h>
#include <functional>
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<class ReturnType, size_t NUM_PARAMS>
struct Caller;
template<class ReturnType>
struct Caller<ReturnType, 0>
{
template<class Fn, class Params>
static ReturnType f(Fn& fn, TypeListValues<Params>&)
{
return fn();
}
template<class T, class MemFn, class Params>
static ReturnType f(T* obj, MemFn& fn, TypeListValues<Params>&)
{
return (obj->*fn)();
}
};
template<class ReturnType>
struct Caller<ReturnType, 1>
{
template<class Fn, class Params>
static ReturnType f(Fn& fn, TypeListValues<Params>& tvl)
{
return fn(tvl.hd);
}
template<class T, class MemFn, class Params>
static ReturnType f(T* obj, MemFn& fn, TypeListValues<Params>& tvl)
{
return (obj->*fn)(tvl.hd);
}
};
template<class ReturnType>
struct Caller<ReturnType, 2>
{
template<class Fn, class Params>
static ReturnType f(Fn& fn, TypeListValues<Params>& tvl)
{
return fn(tvl.hd, tvl.tl.hd);
}
template<class T, class MemFn, class Params>
static ReturnType f(T* obj, MemFn& fn, TypeListValues<Params>& tvl)
{
return (obj->*fn)(tvl.hd, tvl.tl.hd);
}
};
template<class ReturnType>
struct Caller<ReturnType, 3>
{
template<class Fn, class Params>
static ReturnType f(Fn& fn, TypeListValues<Params>& tvl)
{
return fn(tvl.hd, tvl.tl.hd, tvl.tl.tl.hd);
}
template<class T, class MemFn, class Params>
static ReturnType f(T* obj, MemFn& fn, TypeListValues<Params>& tvl)
{
return (obj->*fn)(tvl.hd, tvl.tl.hd, tvl.tl.tl.hd);
}
};
template<class ReturnType>
struct Caller<ReturnType, 4>
{
template<class Fn, class Params>
static ReturnType f(Fn& fn, TypeListValues<Params>& tvl)
{
return fn(tvl.hd, tvl.tl.hd, tvl.tl.tl.hd, tvl.tl.tl.tl.hd);
}
template<class T, class MemFn, class Params>
static ReturnType f(T* obj, MemFn& fn, TypeListValues<Params>& tvl)
{
return (obj->*fn)(tvl.hd, tvl.tl.hd, tvl.tl.tl.hd, tvl.tl.tl.tl.hd);
}
};
template<class ReturnType>
struct Caller<ReturnType, 5>
{
template<class Fn, class Params>
static ReturnType f(Fn& fn, TypeListValues<Params>& tvl)
{
return fn(tvl.hd, tvl.tl.hd, tvl.tl.tl.hd, tvl.tl.tl.tl.hd, tvl.tl.tl.tl.tl.hd);
}
template<class T, class MemFn, class Params>
static ReturnType f(T* obj, MemFn& fn, TypeListValues<Params>& 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<class ReturnType>
struct Caller<ReturnType, 6>
{
template<class Fn, class Params>
static ReturnType f(Fn& fn, TypeListValues<Params>& 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<class T, class MemFn, class Params>
static ReturnType f(T* obj, MemFn& fn, TypeListValues<Params>& 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<class ReturnType>
struct Caller<ReturnType, 7>
{
template<class Fn, class Params>
static ReturnType f(Fn& fn, TypeListValues<Params>& 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<class T, class MemFn, class Params>
static ReturnType f(T* obj, MemFn& fn, TypeListValues<Params>& 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<class ReturnType>
struct Caller<ReturnType, 8>
{
template<class Fn, class Params>
static ReturnType f(Fn& fn, TypeListValues<Params>& 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<class T, class MemFn, class Params>
static ReturnType f(T* obj, MemFn& fn, TypeListValues<Params>& 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<class ReturnType>
struct Caller<ReturnType, 9>
{
template<class Fn, class Params>
static ReturnType f(Fn& fn, TypeListValues<Params>& 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<class T, class MemFn, class Params>
static ReturnType f(T* obj, MemFn& fn, TypeListValues<Params>& 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<class ReturnType, class Fn, class Params>
ReturnType doCall(Fn& fn, TypeListValues<Params>& tvl)
{
return Caller<ReturnType, TypeListSize<Params>::value>::f(fn, tvl);
}
template<class ReturnType, class T, class MemFn, class Params>
ReturnType doCall(T* obj, MemFn& fn, TypeListValues<Params>& tvl)
{
return Caller<ReturnType, TypeListSize<Params>::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<class MemFn, class D = MemFn>
struct FuncTraits
{
};
/* Ordinary function pointers. */
template<class R, class... ParamList>
struct FuncTraits<R (*)(ParamList...)>
{
static bool const isMemberFunction = false;
using DeclType = R (*)(ParamList...);
using ReturnType = R;
using Params = typename MakeTypeList<ParamList...>::Result;
static R call(const DeclType& fp, TypeListValues<Params>& tvl) { return doCall<R>(fp, tvl); }
};
/* Windows: WINAPI (a.k.a. __stdcall) function pointers. */
#ifdef _M_IX86 // Windows 32bit only
template<class R, class... ParamList>
struct FuncTraits<R(__stdcall*)(ParamList...)>
{
static bool const isMemberFunction = false;
using DeclType = R(__stdcall*)(ParamList...);
using ReturnType = R;
using Params = typename MakeTypeList<ParamList...>::Result;
static R call(const DeclType& fp, TypeListValues<Params>& tvl) { return doCall<R>(fp, tvl); }
};
#endif // _M_IX86
/* Non-const member function pointers. */
template<class T, class R, class... ParamList>
struct FuncTraits<R (T::*)(ParamList...)>
{
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<ParamList...>::Result;
static R call(ClassType* obj, const DeclType& fp, TypeListValues<Params>& tvl)
{
return doCall<R>(obj, fp, tvl);
}
};
/* Const member function pointers. */
template<class T, class R, class... ParamList>
struct FuncTraits<R (T::*)(ParamList...) const>
{
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<ParamList...>::Result;
static R call(const ClassType* obj, const DeclType& fp, TypeListValues<Params>& tvl)
{
return doCall<R>(obj, fp, tvl);
}
};
/* std::function */
template<class R, class... ParamList>
struct FuncTraits<std::function<R(ParamList...)>>
{
static bool const isMemberFunction = false;
static bool const isConstMemberFunction = false;
using DeclType = std::function<R(ParamList...)>;
using ReturnType = R;
using Params = typename MakeTypeList<ParamList...>::Result;
static ReturnType call(DeclType& fn, TypeListValues<Params>& tvl)
{
return doCall<ReturnType>(fn, tvl);
}
};
template<class ReturnType, class Params, int startParam>
struct Invoke
{
template<class Fn>
static int run(lua_State* L, Fn& fn)
{
try
{
ArgList<Params, startParam> args(L);
Stack<ReturnType>::push(L, FuncTraits<Fn>::call(fn, args));
return 1;
}
catch (const std::exception& e)
{
return luaL_error(L, e.what());
}
}
template<class T, class MemFn>
static int run(lua_State* L, T* object, const MemFn& fn)
{
try
{
ArgList<Params, startParam> args(L);
Stack<ReturnType>::push(L, FuncTraits<MemFn>::call(object, fn, args));
return 1;
}
catch (const std::exception& e)
{
return luaL_error(L, e.what());
}
}
};
template<class Params, int startParam>
struct Invoke<void, Params, startParam>
{
template<class Fn>
static int run(lua_State* L, Fn& fn)
{
try
{
ArgList<Params, startParam> args(L);
FuncTraits<Fn>::call(fn, args);
return 0;
}
catch (const std::exception& e)
{
return luaL_error(L, e.what());
}
}
template<class T, class MemFn>
static int run(lua_State* L, T* object, const MemFn& fn)
{
try
{
ArgList<Params, startParam> args(L);
FuncTraits<MemFn>::call(object, fn, args);
return 0;
}
catch (const std::exception& e)
{
return luaL_error(L, e.what());
}
}
};
} // namespace detail
} // namespace luabridge

View File

@@ -0,0 +1,150 @@
// https://github.com/vinniefalco/LuaBridge
// Copyright 2018, Dmitry Tarakanov
// Copyright 2012, Vinnie Falco <vinnie.falco@gmail.com>
// SPDX-License-Identifier: MIT
#pragma once
#include <LuaBridge/detail/LuaRef.h>
#include <utility>
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<LuaRef, LuaRef> 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

View File

@@ -0,0 +1,104 @@
// https://github.com/vinniefalco/LuaBridge
// Copyright 2012, Vinnie Falco <vinnie.falco@gmail.com>
// Copyright 2008, Nigel Atkinson <suprapilot+LuaCode@gmail.com>
// SPDX-License-Identifier: MIT
#pragma once
#include <exception>
#include <string>
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<class Exception>
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

View File

@@ -0,0 +1,126 @@
// https://github.com/vinniefalco/LuaBridge
// Copyright 2012, Vinnie Falco <vinnie.falco@gmail.com>
// Copyright 2007, Nathan Reed
// SPDX-License-Identifier: MIT
#pragma once
#include <cassert>
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<void*>(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<void*>(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

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,58 @@
// https://github.com/vinniefalco/LuaBridge
// Copyright 2012, Vinnie Falco <vinnie.falco@gmail.com>
// 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<class T>
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

View File

@@ -0,0 +1,535 @@
// https://github.com/vinniefalco/LuaBridge
// Copyright 2019, Dmitry Tarakanov
// Copyright 2012, Vinnie Falco <vinnie.falco@gmail.com>
// Copyright 2007, Nathan Reed
// SPDX-License-Identifier: MIT
#pragma once
#include <LuaBridge/detail/LuaHelpers.h>
#include <LuaBridge/detail/Userdata.h>
#include <string>
#ifdef LUABRIDGE_CXX17
#include <string_view>
#endif
namespace luabridge {
/// Lua stack traits for C++ types.
///
/// @tparam T A C++ type.
///
template<class T>
struct Stack;
template<>
struct Stack<void>
{
static void push(lua_State*) {}
};
//------------------------------------------------------------------------------
/**
Receive the lua_State* as an argument.
*/
template<>
struct Stack<lua_State*>
{
static lua_State* get(lua_State* L, int) { return L; }
};
//------------------------------------------------------------------------------
/**
Stack specialization for a lua_CFunction.
*/
template<>
struct Stack<lua_CFunction>
{
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<int>
{
static void push(lua_State* L, int value)
{
lua_pushinteger(L, static_cast<lua_Integer>(value));
}
static int get(lua_State* L, int index)
{
return static_cast<int>(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<unsigned int>
{
static void push(lua_State* L, unsigned int value)
{
lua_pushinteger(L, static_cast<lua_Integer>(value));
}
static unsigned int get(lua_State* L, int index)
{
return static_cast<unsigned int>(luaL_checkinteger(L, index));
}
static bool isInstance(lua_State* L, int index) { return Stack<int>::isInstance(L, index); }
};
//------------------------------------------------------------------------------
/**
Stack specialization for `unsigned char`.
*/
template<>
struct Stack<unsigned char>
{
static void push(lua_State* L, unsigned char value)
{
lua_pushinteger(L, static_cast<lua_Integer>(value));
}
static unsigned char get(lua_State* L, int index)
{
return static_cast<unsigned char>(luaL_checkinteger(L, index));
}
static bool isInstance(lua_State* L, int index) { return Stack<int>::isInstance(L, index); }
};
//------------------------------------------------------------------------------
/**
Stack specialization for `short`.
*/
template<>
struct Stack<short>
{
static void push(lua_State* L, short value)
{
lua_pushinteger(L, static_cast<lua_Integer>(value));
}
static short get(lua_State* L, int index)
{
return static_cast<short>(luaL_checkinteger(L, index));
}
static bool isInstance(lua_State* L, int index) { return Stack<int>::isInstance(L, index); }
};
//------------------------------------------------------------------------------
/**
Stack specialization for `unsigned short`.
*/
template<>
struct Stack<unsigned short>
{
static void push(lua_State* L, unsigned short value)
{
lua_pushinteger(L, static_cast<lua_Integer>(value));
}
static unsigned short get(lua_State* L, int index)
{
return static_cast<unsigned short>(luaL_checkinteger(L, index));
}
static bool isInstance(lua_State* L, int index) { return Stack<int>::isInstance(L, index); }
};
//------------------------------------------------------------------------------
/**
Stack specialization for `long`.
*/
template<>
struct Stack<long>
{
static void push(lua_State* L, long value)
{
lua_pushinteger(L, static_cast<lua_Integer>(value));
}
static long get(lua_State* L, int index)
{
return static_cast<long>(luaL_checkinteger(L, index));
}
static bool isInstance(lua_State* L, int index) { return Stack<int>::isInstance(L, index); }
};
//------------------------------------------------------------------------------
/**
Stack specialization for `unsigned long`.
*/
template<>
struct Stack<unsigned long>
{
static void push(lua_State* L, unsigned long value)
{
lua_pushinteger(L, static_cast<lua_Integer>(value));
}
static unsigned long get(lua_State* L, int index)
{
return static_cast<unsigned long>(luaL_checkinteger(L, index));
}
static bool isInstance(lua_State* L, int index) { return Stack<int>::isInstance(L, index); }
};
//------------------------------------------------------------------------------
/**
* Stack specialization for `long long`.
*/
template<>
struct Stack<long long>
{
static void push(lua_State* L, long long value)
{
lua_pushinteger(L, static_cast<lua_Integer>(value));
}
static long long get(lua_State* L, int index)
{
return static_cast<long long>(luaL_checkinteger(L, index));
}
static bool isInstance(lua_State* L, int index) { return Stack<int>::isInstance(L, index); }
};
//------------------------------------------------------------------------------
/**
* Stack specialization for `unsigned long long`.
*/
template<>
struct Stack<unsigned long long>
{
static void push(lua_State* L, unsigned long long value)
{
lua_pushinteger(L, static_cast<lua_Integer>(value));
}
static unsigned long long get(lua_State* L, int index)
{
return static_cast<unsigned long long>(luaL_checkinteger(L, index));
}
static bool isInstance(lua_State* L, int index) { return Stack<int>::isInstance(L, index); }
};
//------------------------------------------------------------------------------
/**
Stack specialization for `float`.
*/
template<>
struct Stack<float>
{
static void push(lua_State* L, float value)
{
lua_pushnumber(L, static_cast<lua_Number>(value));
}
static float get(lua_State* L, int index)
{
return static_cast<float>(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<double>
{
static void push(lua_State* L, double value)
{
lua_pushnumber(L, static_cast<lua_Number>(value));
}
static double get(lua_State* L, int index)
{
return static_cast<double>(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<bool>
{
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<char>
{
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<char const*>
{
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<std::string>
{
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<std::string_view>
{
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<class T>
struct StackOpSelector<T&, false>
{
typedef T ReturnType;
static void push(lua_State* L, T& value) { Stack<T>::push(L, value); }
static ReturnType get(lua_State* L, int index) { return Stack<T>::get(L, index); }
static bool isInstance(lua_State* L, int index) { return Stack<T>::isInstance(L, index); }
};
template<class T>
struct StackOpSelector<const T&, false>
{
typedef T ReturnType;
static void push(lua_State* L, const T& value) { Stack<T>::push(L, value); }
static ReturnType get(lua_State* L, int index) { return Stack<T>::get(L, index); }
static bool isInstance(lua_State* L, int index) { return Stack<T>::isInstance(L, index); }
};
template<class T>
struct StackOpSelector<T*, false>
{
typedef T ReturnType;
static void push(lua_State* L, T* value) { Stack<T>::push(L, *value); }
static ReturnType get(lua_State* L, int index) { return Stack<T>::get(L, index); }
static bool isInstance(lua_State* L, int index) { return Stack<T>::isInstance(L, index); }
};
template<class T>
struct StackOpSelector<const T*, false>
{
typedef T ReturnType;
static void push(lua_State* L, const T* value) { Stack<T>::push(L, *value); }
static ReturnType get(lua_State* L, int index) { return Stack<T>::get(L, index); }
static bool isInstance(lua_State* L, int index) { return Stack<T>::isInstance(L, index); }
};
} // namespace detail
template<class T>
struct Stack<T&>
{
typedef detail::StackOpSelector<T&, detail::IsUserdata<T>::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<class T>
struct Stack<const T&>
{
typedef detail::StackOpSelector<const T&, detail::IsUserdata<T>::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<class T>
struct Stack<T*>
{
typedef detail::StackOpSelector<T*, detail::IsUserdata<T>::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<class T>
struct Stack<const T*>
{
typedef detail::StackOpSelector<const T*, detail::IsUserdata<T>::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<class T>
void push(lua_State* L, T t)
{
Stack<T>::push(L, t);
}
//------------------------------------------------------------------------------
/**
* Get an object from the Lua stack.
*/
template<class T>
T get(lua_State* L, int index)
{
return Stack<T>::get(L, index);
}
//------------------------------------------------------------------------------
/**
* Check whether an object on the Lua stack is of type T.
*/
template<class T>
bool isInstance(lua_State* L, int index)
{
return Stack<T>::isInstance(L, index);
}
} // namespace luabridge

View File

@@ -0,0 +1,183 @@
// https://github.com/vinniefalco/LuaBridge
// Copyright 2012, Vinnie Falco <vinnie.falco@gmail.com>
// 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 <LuaBridge/detail/Config.h>
#include <LuaBridge/detail/Stack.h>
#include <string>
#include <typeinfo>
namespace luabridge {
namespace detail {
/**
None type means void parameters or return value.
*/
typedef void None;
template<typename Head, typename Tail = None>
struct TypeList
{
typedef Tail TailType;
};
template<class List>
struct TypeListSize
{
static const size_t value = TypeListSize<typename List::TailType>::value + 1;
};
template<>
struct TypeListSize<None>
{
static const size_t value = 0;
};
template<class... Params>
struct MakeTypeList;
template<class Param, class... Params>
struct MakeTypeList<Param, Params...>
{
using Result = TypeList<Param, typename MakeTypeList<Params...>::Result>;
};
template<>
struct MakeTypeList<>
{
using Result = None;
};
/**
A TypeList with actual values.
*/
template<typename List>
struct TypeListValues
{
static std::string const tostring(bool) { return ""; }
};
/**
TypeListValues recursive template definition.
*/
template<typename Head, typename Tail>
struct TypeListValues<TypeList<Head, Tail>>
{
Head hd;
TypeListValues<Tail> tl;
TypeListValues(Head hd_, TypeListValues<Tail> 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<Tail>::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<typename Head, typename Tail>
struct TypeListValues<TypeList<Head&, Tail>>
{
Head hd;
TypeListValues<Tail> tl;
TypeListValues(Head& hd_, TypeListValues<Tail> 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<Tail>::tostring(true);
}
};
template<typename Head, typename Tail>
struct TypeListValues<TypeList<Head const&, Tail>>
{
Head hd;
TypeListValues<Tail> tl;
TypeListValues(Head const& hd_, const TypeListValues<Tail>& 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<Tail>::tostring(true);
}
};
//==============================================================================
/**
Subclass of a TypeListValues constructable from the Lua stack.
*/
template<typename List, int Start = 1>
struct ArgList
{
};
template<int Start>
struct ArgList<None, Start> : public TypeListValues<None>
{
ArgList(lua_State*) {}
};
template<typename Head, typename Tail, int Start>
struct ArgList<TypeList<Head, Tail>, Start> : public TypeListValues<TypeList<Head, Tail>>
{
ArgList(lua_State* L)
: TypeListValues<TypeList<Head, Tail>>(Stack<Head>::get(L, Start),
ArgList<Tail, Start + 1>(L))
{
}
};
} // namespace detail
} // namespace luabridge

View File

@@ -0,0 +1,112 @@
// https://github.com/vinniefalco/LuaBridge
// Copyright 2019, Dmitry Tarakanov
// Copyright 2012, Vinnie Falco <vinnie.falco@gmail.com>
// SPDX-License-Identifier: MIT
#pragma once
#include <LuaBridge/detail/Config.h>
#include <string>
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 <class T>
struct ContainerTraits <ContainerType <T>>
{
typedef typename T Type;
static T* get (ContainerType <T> const& c)
{
return c.get (); // Implementation-dependent on ContainerType
}
};
*/
template<class T>
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<typename T>
class isContainer
{
private:
typedef char yes[1]; // sizeof (yes) == 1
typedef char no[2]; // sizeof (no) == 2
template<typename C>
static no& test(typename C::isNotContainer*);
template<typename>
static yes& test(...);
public:
static const bool value = sizeof(test<ContainerTraits<T>>(0)) == sizeof(yes);
};
/** Determine if T is const qualified.
*/
/** @{ */
template<class T>
struct isConst
{
static bool const value = false;
};
template<class T>
struct isConst<T const>
{
static bool const value = true;
};
/** @} */
/** Remove the const qualifier from T.
*/
/** @{ */
template<class T>
struct removeConst
{
typedef T Type;
};
template<class T>
struct removeConst<T const>
{
typedef T Type;
};
/**@}*/
};
} // namespace detail
} // namespace luabridge

View File

@@ -0,0 +1,769 @@
// https://github.com/vinniefalco/LuaBridge
// Copyright 2019, Dmitry Tarakanov
// Copyright 2012, Vinnie Falco <vinnie.falco@gmail.com>
// SPDX-License-Identifier: MIT
#pragma once
#include <LuaBridge/detail/ClassInfo.h>
#include <LuaBridge/detail/TypeTraits.h>
#include <cassert>
#include <stdexcept>
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<Userdata*>(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<Userdata*>(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<class T>
static Userdata* getExact(lua_State* L, int index)
{
return getExactClass(L, index, detail::getClassRegistryKey<T>());
}
//--------------------------------------------------------------------------
/**
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<class T>
static T* get(lua_State* L, int index, bool canBeConst)
{
if (lua_isnil(L, index))
return 0;
return static_cast<T*>(getClass(L,
index,
detail::getConstRegistryKey<T>(),
detail::getClassRegistryKey<T>(),
canBeConst)
->getPointer());
}
template<class T>
static bool isInstance(lua_State* L, int index)
{
return isInstance(L, index, detail::getClassRegistryKey<T>());
}
};
//----------------------------------------------------------------------------
/**
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 T>
class UserdataValue : public Userdata
{
private:
UserdataValue(UserdataValue<T> const&);
UserdataValue<T> operator=(UserdataValue<T> 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<T>* place(lua_State* const L)
{
UserdataValue<T>* const ud =
new (lua_newuserdata(L, sizeof(UserdataValue<T>))) UserdataValue<T>();
lua_rawgetp(L, LUA_REGISTRYINDEX, detail::getClassRegistryKey<T>());
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<class U>
static inline void push(lua_State* const L, U const& u)
{
UserdataValue<T>* 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<T*>(&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<void*>(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<class T>
static void push(lua_State* const L, T* const p)
{
if (p)
push(L, p, getClassRegistryKey<T>());
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<class T>
static void push(lua_State* const L, T const* const p)
{
if (p)
push(L, p, getConstRegistryKey<T>());
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 C>
class UserdataShared : public Userdata
{
private:
UserdataShared(UserdataShared<C> const&);
UserdataShared<C>& operator=(UserdataShared<C> const&);
typedef typename TypeTraits::removeConst<typename ContainerTraits<C>::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<class U>
explicit UserdataShared(U const& u) : m_c(u)
{
m_p = const_cast<void*>(reinterpret_cast<void const*>((ContainerTraits<C>::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<class U>
explicit UserdataShared(U* u) : m_c(u)
{
m_p = const_cast<void*>(reinterpret_cast<void const*>((ContainerTraits<C>::get(m_c))));
}
};
//----------------------------------------------------------------------------
//
// SFINAE helpers.
//
// non-const objects
template<class C, bool makeObjectConst>
struct UserdataSharedHelper
{
typedef typename TypeTraits::removeConst<typename ContainerTraits<C>::Type>::Type T;
static void push(lua_State* L, C const& c)
{
if (ContainerTraits<C>::get(c) != 0)
{
new (lua_newuserdata(L, sizeof(UserdataShared<C>))) UserdataShared<C>(c);
lua_rawgetp(L, LUA_REGISTRYINDEX, getClassRegistryKey<T>());
// 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<C>))) UserdataShared<C>(t);
lua_rawgetp(L, LUA_REGISTRYINDEX, getClassRegistryKey<T>());
// 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<class C>
struct UserdataSharedHelper<C, true>
{
typedef typename TypeTraits::removeConst<typename ContainerTraits<C>::Type>::Type T;
static void push(lua_State* L, C const& c)
{
if (ContainerTraits<C>::get(c) != 0)
{
new (lua_newuserdata(L, sizeof(UserdataShared<C>))) UserdataShared<C>(c);
lua_rawgetp(L, LUA_REGISTRYINDEX, getConstRegistryKey<T>());
// 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<C>))) UserdataShared<C>(t);
lua_rawgetp(L, LUA_REGISTRYINDEX, getConstRegistryKey<T>());
// 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<class C, bool byContainer>
struct StackHelper
{
static void push(lua_State* L, C const& c)
{
UserdataSharedHelper<C, TypeTraits::isConst<typename ContainerTraits<C>::Type>::value>::
push(L, c);
}
typedef typename TypeTraits::removeConst<typename ContainerTraits<C>::Type>::Type T;
static C get(lua_State* L, int index) { return Userdata::get<T>(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<class T>
struct StackHelper<T, false>
{
static inline void push(lua_State* L, T const& t) { UserdataValue<T>::push(L, t); }
static inline T const& get(lua_State* L, int index)
{
return *Userdata::get<T>(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<class C, bool byContainer>
struct RefStackHelper
{
typedef C return_type;
static inline void push(lua_State* L, C const& t)
{
UserdataSharedHelper<C, TypeTraits::isConst<typename ContainerTraits<C>::Type>::value>::
push(L, t);
}
typedef typename TypeTraits::removeConst<typename ContainerTraits<C>::Type>::Type T;
static return_type get(lua_State* L, int index) { return Userdata::get<T>(L, index, true); }
};
template<class T>
struct RefStackHelper<T, false>
{
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<T>(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<class T>
struct Void
{
typedef void Type;
};
/**
* Trait class that selects whether to return a user registered
* class object by value or by reference.
*/
template<class T, class Enabler = void>
struct UserdataGetter
{
typedef T* ReturnType;
static ReturnType get(lua_State* L, int index) { return Userdata::get<T>(L, index, false); }
};
template<class T>
struct UserdataGetter<T, typename Void<T (*)()>::Type>
{
typedef T ReturnType;
static ReturnType get(lua_State* L, int index)
{
return StackHelper<T, TypeTraits::isContainer<T>::value>::get(L, index);
}
};
} // namespace detail
//==============================================================================
/**
Lua stack conversions for class objects passed by value.
*/
template<class T>
struct Stack
{
typedef void IsUserdata;
typedef detail::UserdataGetter<T> Getter;
typedef typename Getter::ReturnType ReturnType;
static void push(lua_State* L, T const& value)
{
using namespace detail;
StackHelper<T, TypeTraits::isContainer<T>::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<T>(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<class T, class Enable = void>
struct IsUserdata
{
static const bool value = false;
};
template<class T>
struct IsUserdata<T, typename Void<typename Stack<T>::IsUserdata>::Type>
{
static const bool value = true;
};
/**
* Trait class that selects a specific push/get implementation.
*/
template<class T, bool isUserdata>
struct StackOpSelector;
// pointer
template<class T>
struct StackOpSelector<T*, true>
{
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<T>(L, index, false); }
static bool isInstance(lua_State* L, int index) { return Userdata::isInstance<T>(L, index); }
};
// pointer to const
template<class T>
struct StackOpSelector<const T*, true>
{
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<T>(L, index, true); }
static bool isInstance(lua_State* L, int index) { return Userdata::isInstance<T>(L, index); }
};
// reference
template<class T>
struct StackOpSelector<T&, true>
{
typedef RefStackHelper<T, TypeTraits::isContainer<T>::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<T>(L, index); }
};
// reference to const
template<class T>
struct StackOpSelector<const T&, true>
{
typedef RefStackHelper<T, TypeTraits::isContainer<T>::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<T>(L, index); }
};
} // namespace detail
} // namespace luabridge

View File

@@ -0,0 +1,125 @@
// https://github.com/vinniefalco/LuaBridge
// Copyright 2019, Dmitry Tarakanov
// Copyright 2012, Vinnie Falco <vinnie.falco@gmail.com>
// Copyright 2007, Nathan Reed
// SPDX-License-Identifier: MIT
#pragma once
#include "LuaBridge/detail/ClassInfo.h"
#include <iostream>
#include <string>
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

View File

@@ -78,11 +78,11 @@
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
<IncludePath>F:\source2\csgo2\csgo2\sdk\protobuf-2.6.1\src;$(IncludePath)</IncludePath>
<IncludePath>$(MSBuildProjectDirectory)\sdk\protobuf-2.6.1\src;$(MSBuildProjectDirectory)\LuaBridge;$(IncludePath)</IncludePath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
<IncludePath>F:\source2\csgo2\csgo2\sdk\protobuf-2.6.1\src;$(IncludePath)</IncludePath>
<IncludePath>$(MSBuildProjectDirectory)\sdk\protobuf-2.6.1\src;$(MSBuildProjectDirectory)\LuaBridge;$(IncludePath)</IncludePath>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
@@ -213,16 +213,25 @@
<ClInclude Include="sdk\interfaces\interfaces.h" />
<ClInclude Include="sdk\player\player.h" />
<ClInclude Include="sdk\player\playerslot.h" />
<ClInclude Include="sdk\public\bitvec.h" />
<ClInclude Include="sdk\public\eiface.h" />
<ClInclude Include="sdk\public\IAppSystem.h" />
<ClInclude Include="sdk\public\iserver.h" />
<ClInclude Include="sdk\public\mathlib.h" />
<ClInclude Include="sdk\public\string_t.h" />
<ClInclude Include="sdk\public\utlmap.h" />
<ClInclude Include="sdk\public\utlrbtree.h" />
<ClInclude Include="sdk\sdk.h" />
<ClInclude Include="sdk\tier1\bufferstring.h" />
<ClInclude Include="sdk\tier1\utlblockmemory.h" />
<ClInclude Include="sdk\tier1\utlfixedmemory.h" />
<ClInclude Include="sdk\tier1\UtlMemory.hpp" />
<ClInclude Include="sdk\tier1\UtlString.hpp" />
<ClInclude Include="sdk\tier1\UtlVector.hpp" />
<ClInclude Include="sdk_tools.h" />
<ClInclude Include="stb.hh" />
<ClInclude Include="tools.h" />
<ClInclude Include="vector.h" />
<ClInclude Include="vmt.h" />
<ClInclude Include="vmthook.h" />
<ClInclude Include="script_callbacks.h" />

View File

@@ -291,6 +291,33 @@
<ClInclude Include="script_callbacks.h">
<Filter>头文件\script_engine</Filter>
</ClInclude>
<ClInclude Include="sdk\public\bitvec.h">
<Filter>头文件\sdk\tier1</Filter>
</ClInclude>
<ClInclude Include="sdk\public\iserver.h">
<Filter>头文件\sdk\public</Filter>
</ClInclude>
<ClInclude Include="sdk\public\string_t.h">
<Filter>头文件\sdk\public</Filter>
</ClInclude>
<ClInclude Include="sdk\public\utlmap.h">
<Filter>头文件\sdk\public</Filter>
</ClInclude>
<ClInclude Include="sdk\public\utlrbtree.h">
<Filter>头文件\sdk\tier1</Filter>
</ClInclude>
<ClInclude Include="sdk\tier1\utlfixedmemory.h">
<Filter>头文件\sdk\tier1</Filter>
</ClInclude>
<ClInclude Include="sdk\tier1\utlblockmemory.h">
<Filter>头文件\sdk\tier1</Filter>
</ClInclude>
<ClInclude Include="sdk\public\mathlib.h">
<Filter>头文件\sdk\public</Filter>
</ClInclude>
<ClInclude Include="vector.h">
<Filter>头文件\native_sdk</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="dllmain.cpp">

View File

@@ -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<CCSPlayerPawn*>(
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());
}

View File

@@ -32,23 +32,33 @@ static void DebugPrintA(const char* format, ...) {
#include "./MinHook/include/MinHook.h"
#include "hash_fnv1a_constexpr.h"
// <20><><EFBFBD>߿<EFBFBD>
#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"

View File

@@ -53,18 +53,35 @@ auto CCSPlayerPawn::GetPlayerController() -> CCSPlayerController*
return nullptr;
}
using SchemaKeyValueMap_t = std::unordered_map<uint32_t, int16_t>;
using SchemaTableMap_t = std::unordered_map<uint32_t, SchemaKeyValueMap_t>;
using SchemaKeyValueMap_t = CUtlMap<uint32_t, SchemaKey>;
using SchemaTableMap_t = CUtlMap<uint32_t, SchemaKeyValueMap_t*>;
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);
}
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);
};

View File

@@ -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<type> 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<std::add_pointer_t<type>>( \
(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<FnNetworkStateChanged>(Offset::NetworkStateChangedPtr)((uintptr_t)(this) + m_chain, m_offset + extra_offset, 0xFFFFFFFF); \
} \
*reinterpret_cast<std::add_pointer_t<type>>((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<type> 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<std::add_pointer_t<type>>( \
(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<std::add_pointer_t<type>>((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<std::add_pointer_t<type>>( \
(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 <typename T>
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<const char**>((uintptr_t)(this) + 0xD8);
}
auto GetStickersSupportedCount() {
return *reinterpret_cast<int*>((uintptr_t)(this) + 0x100);
}
auto GetSimpleWeaponName() {
return *reinterpret_cast<const char**>((uintptr_t)(this) + 0x210);
}
auto GetLoadoutSlot() {
return *reinterpret_cast<int*>((uintptr_t)(this) + 0x2E8);
}
char pad0[0x8]; // vtable
void* m_pKVItem;
uint16_t m_nDefIndex;
CUtlVector_NativeSdk<uint16_t> 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<void*> 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<CGameEntitySystem**>((uintptr_t)(this) + 0x58);
}
};
};
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)
};

View File

@@ -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<CSchemaSystem*>(
schemasystem.FindInterface("SchemaSystem_001").Get());
// engine.dll
//InterFaces::GameEventManager = reinterpret_cast<IGameEventManager2*>(
// engine.FindInterface("GameEventSystemServerV001").Get());
//InterFaces::GameEventManager = reinterpret_cast<IGameEventManager2*>(engine.FindInterface("GameEventSystemServerV001").Get());
InterFaces::ILocalize = reinterpret_cast<CLocalize*>(localize.FindInterface("Localize_001").Get());
InterFaces::GameResourceServiceServer =
reinterpret_cast<CGameResourceService*>(
engine.FindInterface("GameResourceServiceServerV001").Get());
InterFaces::IVEngineServer = reinterpret_cast<IVEngineServer2*>(
engine.FindInterface("Source2EngineToServer001").Get());
// server.dll
InterFaces::INetworkServerServiceInteFace = reinterpret_cast<INetworkServerService*>(
engine.FindInterface("NetworkServerService_001").Get());
InterFaces::IServerGameClient = reinterpret_cast<IServerGameClients*>(
server.FindInterface("Source2GameClients001").Get());
InterFaces::ISource2ServerInterFace = reinterpret_cast<ISource2Server*>(
@@ -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

View File

@@ -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

View File

@@ -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 {
// <20><><EFBFBD><EFBFBD><EFBFBD>Ƿ<EFBFBD><C7B7><EFBFBD>ֵ<EFBFBD><D6B5><EFBFBD><EFBFBD>,<2C><><EFBFBD><EFBFBD>ֵ<EFBFBD><D6B5><EFBFBD><EFBFBD>Ҫ<EFBFBD>Լ<EFBFBD>push<73><68>stack<63><6B>
auto luaApi_ListenToGameEvent(lua_State* luaVm) -> int {
@@ -21,7 +33,8 @@ auto luaApi_ListenToGameEvent(lua_State* luaVm) -> int {
}
// <20><><EFBFBD>ص<EFBFBD><D8B5><EFBFBD><EFBFBD>ӵ<EFBFBD>ӳ<EFBFBD><D3B3><EFBFBD><EFBFBD>
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); // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ջ
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<CCSPlayerController*>(player);
const auto weaponServices = playerController->m_hPawn().Get<CCSPlayerPawn>()->m_pWeaponServices();
if (weaponServices == nullptr) {
break;
}
const auto activeWeapon = weaponServices->m_hActiveWeapon().Get<CBasePlayerWeapon>();
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<CCSPlayerController*>(player);
const auto weaponServices = playerController->m_hPawn().Get<CCSPlayerPawn>()->m_pWeaponServices();
if (weaponServices == nullptr) {
break;
}
const auto activeWeapon = weaponServices->m_hActiveWeapon().Get<CBasePlayerWeapon>();
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<int>(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);
//<2F>Ҳ<EFBFBD>ϲ<EFBFBD><CFB2><EFBFBD><EFBFBD>
luabridge::getGlobalNamespace(luaVm)
.beginClass<_luaApi_WeaponInfo>("WeaponInfo")
.addConstructor<void(*) (void)>()
.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

View File

@@ -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);

View File

@@ -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

View File

@@ -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";

1397
csgo2/sdk/public/bitvec.h Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -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;

133
csgo2/sdk/public/iserver.h Normal file
View File

@@ -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<CEventIDManager_Default>*/ void*) = 0;
virtual void OnLoopDeactivate(const EngineLoopState_t& loopState, /*CEventDispatcher<CEventIDManager_Default>*/ void*) = 0;
virtual bool IsActive(void) const = 0;
virtual void SetActive(bool) = 0;
virtual void SetName(const char* pszName) = 0;
virtual void RegisterEventMap( /*CEventDispatcher<CEventIDManager_Default>*/ 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;
};

View File

@@ -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;
}

114
csgo2/sdk/public/string_t.h Normal file
View File

@@ -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 <cstddef>
#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<const char *>( offset ) : "" )
//-----------------------------------------------------------------------------
// Purpose: Given a C string, obtain a string_t
//-----------------------------------------------------------------------------
#define MAKE_STRING( str ) ( ( *str != 0 ) ? reinterpret_cast<int>( 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

200
csgo2/sdk/public/utlmap.h Normal file
View File

@@ -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 <typename K, typename T, typename I = short unsigned int, typename LF = bool (*)(const K&, const K&)>
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<Node_t, I, CKeyLess> CTree;
CTree *AccessTree() { return &m_Tree; }
protected:
CTree m_Tree;
};
//-----------------------------------------------------------------------------
#endif // UTLMAP_H

1546
csgo2/sdk/public/utlrbtree.h Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,6 @@
#pragma once
#include <limits.h>
#include <cstdint>
#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 <class T>
inline T* Construct(T* pMemory)
{
return ::new(pMemory) T;
}
template <class T>
inline void Destruct(T* pMemory)
{
pMemory->~T();
#ifdef _DEBUG
memset((void*)pMemory, 0xDD, sizeof(T));
#endif
}
#include "../head.h"

View File

@@ -1,5 +1,5 @@
#pragma once
#include <stdint.h>
#include <cstring>
#include "UtlMemory.hpp"
#define _Utl_Vector_assert

View File

@@ -0,0 +1,345 @@
//===== Copyright <20> 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<T,I>::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<T,I>::~CUtlBlockMemory()
{
Purge();
}
//-----------------------------------------------------------------------------
// Fast swap
//-----------------------------------------------------------------------------
template< class T, class I >
void CUtlBlockMemory<T,I>::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<T,I>::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<T,I>::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<T,I>::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<T,I>::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<T,I>::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<T,I>::NumAllocated() const
{
return m_nBlocks * NumElementsInBlock();
}
//-----------------------------------------------------------------------------
// Is element index valid?
//-----------------------------------------------------------------------------
template< class T, class I >
inline bool CUtlBlockMemory<T,I>::IsIdxValid( I i ) const
{
return ( i >= 0 ) && ( MajorIndex( i ) < m_nBlocks );
}
template< class T, class I >
void CUtlBlockMemory<T,I>::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<T,I>::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<T,I>::EnsureCapacity( int num )
{
Grow( num - NumAllocated() );
}
//-----------------------------------------------------------------------------
// Memory deallocation
//-----------------------------------------------------------------------------
template< class T, class I >
void CUtlBlockMemory<T,I>::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<T,I>::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

View File

@@ -0,0 +1,337 @@
//===== Copyright <20> 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<T>::CUtlFixedMemory( int nGrowSize, int nInitAllocationCount )
: m_pBlocks( 0 ), m_nAllocationCount( 0 ), m_nGrowSize( 0 )
{
Init( nGrowSize, nInitAllocationCount );
}
template< class T >
CUtlFixedMemory<T>::~CUtlFixedMemory()
{
Purge();
}
//-----------------------------------------------------------------------------
// Fast swap - WARNING: Swap invalidates all ptr-based indices!!!
//-----------------------------------------------------------------------------
template< class T >
void CUtlFixedMemory<T>::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<T>::Init( int nGrowSize /* = 0 */, int nInitSize /* = 0 */ )
{
Purge();
m_nGrowSize = nGrowSize;
Grow( nInitSize );
}
//-----------------------------------------------------------------------------
// element access
//-----------------------------------------------------------------------------
template< class T >
inline T& CUtlFixedMemory<T>::operator[]( intp i )
{
return *( T* )i;
}
template< class T >
inline const T& CUtlFixedMemory<T>::operator[]( intp i ) const
{
return *( T* )i;
}
template< class T >
inline T& CUtlFixedMemory<T>::Element( intp i )
{
return *( T* )i;
}
template< class T >
inline const T& CUtlFixedMemory<T>::Element( intp i ) const
{
return *( T* )i;
}
//-----------------------------------------------------------------------------
// Size
//-----------------------------------------------------------------------------
template< class T >
inline int CUtlFixedMemory<T>::NumAllocated() const
{
return m_nAllocationCount;
}
//-----------------------------------------------------------------------------
// Is element index valid?
//-----------------------------------------------------------------------------
template< class T >
inline bool CUtlFixedMemory<T>::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<T>::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<T>::EnsureCapacity( int num )
{
Grow( num - NumAllocated() );
}
//-----------------------------------------------------------------------------
// Memory deallocation
//-----------------------------------------------------------------------------
template< class T >
void CUtlFixedMemory<T>::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

404
csgo2/vector.h Normal file
View File

@@ -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<Vector*>(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;
}