Fractured: Paragon core hooks, mod-paragon, mod-ale, Docker build cap
- Track mod-paragon and mod-ale (un-ignore modules in .gitignore). - Ship docker-compose.override.yml with CMAKE_EXTRA_OPTIONS for LuaJIT (mod-ale). - Dockerfile: CBUILD_PARALLEL default to limit OOM under Docker/WSL2. - Core: CLASS_PARAGON sticky combo points (DetachComboTarget), selection rebind, Spell::CheckPower rune path for multi-resource Paragon. - spell_dk_death_rune: IsClass(CLASS_DEATH_KNIGHT, CLASS_CONTEXT_ABILITY) for Blood of the North / Reaping / DRM on Paragon. - Remove temporary Paragon CheckPower logging. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,375 @@
|
||||
/*
|
||||
* Copyright (C) 2010 - 2025 Eluna Lua Engine <https://elunaluaengine.github.io/>
|
||||
* This program is free software licensed under GPL version 3
|
||||
* Please see the included DOCS/LICENSE.md for more information
|
||||
*/
|
||||
|
||||
#ifndef _BINDING_MAP_H
|
||||
#define _BINDING_MAP_H
|
||||
|
||||
#include <memory>
|
||||
#include "Common.h"
|
||||
#include "ALEUtility.h"
|
||||
#include <type_traits>
|
||||
|
||||
extern "C"
|
||||
{
|
||||
#include "lua.h"
|
||||
#include "lauxlib.h"
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* A set of bindings from keys of type `K` to Lua references.
|
||||
*/
|
||||
template<typename K>
|
||||
class BindingMap : public ALEUtil::Lockable
|
||||
{
|
||||
private:
|
||||
lua_State* L;
|
||||
uint64 maxBindingID;
|
||||
|
||||
struct Binding
|
||||
{
|
||||
uint64 id;
|
||||
lua_State* L;
|
||||
uint32 remainingShots;
|
||||
int functionReference;
|
||||
|
||||
Binding(lua_State* L, uint64 id, int functionReference, uint32 remainingShots) :
|
||||
id(id),
|
||||
L(L),
|
||||
remainingShots(remainingShots),
|
||||
functionReference(functionReference)
|
||||
{ }
|
||||
|
||||
~Binding()
|
||||
{
|
||||
luaL_unref(L, LUA_REGISTRYINDEX, functionReference);
|
||||
}
|
||||
};
|
||||
|
||||
typedef std::vector< std::unique_ptr<Binding> > BindingList;
|
||||
|
||||
std::unordered_map<K, BindingList> bindings;
|
||||
/*
|
||||
* This table is for fast removal of bindings by ID.
|
||||
*
|
||||
* Instead of having to look through (potentially) every BindingList to find
|
||||
* the Binding with the right ID, this allows you to go directly to the
|
||||
* BindingList that might have the Binding with that ID.
|
||||
*
|
||||
* However, you must be careful not to store pointers to BindingLists
|
||||
* that no longer exist (see `void Clear(const K& key)` implementation).
|
||||
*/
|
||||
std::unordered_map<uint64, BindingList*> id_lookup_table;
|
||||
|
||||
public:
|
||||
BindingMap(lua_State* L) :
|
||||
L(L),
|
||||
maxBindingID(0)
|
||||
{ }
|
||||
|
||||
/*
|
||||
* Insert a new binding from `key` to `ref`, which lasts for `shots`-many pushes.
|
||||
*
|
||||
* If `shots` is 0, it will never automatically expire, but can still be
|
||||
* removed with `Clear` or `Remove`.
|
||||
*/
|
||||
uint64 Insert(const K& key, int ref, uint32 shots)
|
||||
{
|
||||
Guard guard(GetLock());
|
||||
|
||||
uint64 id = (++maxBindingID);
|
||||
BindingList& list = bindings[key];
|
||||
list.push_back(std::unique_ptr<Binding>(new Binding(L, id, ref, shots)));
|
||||
id_lookup_table[id] = &list;
|
||||
return id;
|
||||
}
|
||||
|
||||
/*
|
||||
* Clear all bindings for `key`.
|
||||
*/
|
||||
void Clear(const K& key)
|
||||
{
|
||||
Guard guard(GetLock());
|
||||
|
||||
if (bindings.empty())
|
||||
return;
|
||||
|
||||
auto iter = bindings.find(key);
|
||||
if (iter == bindings.end())
|
||||
return;
|
||||
|
||||
BindingList& list = iter->second;
|
||||
|
||||
// Remove all pointers to `list` from `id_lookup_table`.
|
||||
for (auto i = list.begin(); i != list.end(); ++i)
|
||||
{
|
||||
std::unique_ptr<Binding>& binding = *i;
|
||||
id_lookup_table.erase(binding->id);
|
||||
}
|
||||
|
||||
bindings.erase(key);
|
||||
}
|
||||
|
||||
/*
|
||||
* Clear all bindings for all keys.
|
||||
*/
|
||||
void Clear()
|
||||
{
|
||||
Guard guard(GetLock());
|
||||
|
||||
if (bindings.empty())
|
||||
return;
|
||||
|
||||
id_lookup_table.clear();
|
||||
bindings.clear();
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove a specific binding identified by `id`.
|
||||
*
|
||||
* If `id` in invalid, nothing is removed.
|
||||
*/
|
||||
void Remove(uint64 id)
|
||||
{
|
||||
Guard guard(GetLock());
|
||||
|
||||
auto iter = id_lookup_table.find(id);
|
||||
if (iter == id_lookup_table.end())
|
||||
return;
|
||||
|
||||
BindingList* list = iter->second;
|
||||
auto i = list->begin();
|
||||
|
||||
for (; i != list->end(); ++i)
|
||||
{
|
||||
std::unique_ptr<Binding>& binding = *i;
|
||||
if (binding->id == id)
|
||||
break;
|
||||
}
|
||||
|
||||
if (i != list->end())
|
||||
list->erase(i);
|
||||
|
||||
// Unconditionally erase the ID in the lookup table because
|
||||
// it was either already invalid, or it's no longer valid.
|
||||
id_lookup_table.erase(id);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check whether `key` has any bindings.
|
||||
*/
|
||||
bool HasBindingsFor(const K& key)
|
||||
{
|
||||
Guard guard(GetLock());
|
||||
|
||||
if (bindings.empty())
|
||||
return false;
|
||||
|
||||
auto result = bindings.find(key);
|
||||
if (result == bindings.end())
|
||||
return false;
|
||||
|
||||
BindingList& list = result->second;
|
||||
return !list.empty();
|
||||
}
|
||||
|
||||
/*
|
||||
* Push all Lua references for `key` onto the stack.
|
||||
*/
|
||||
void PushRefsFor(const K& key)
|
||||
{
|
||||
Guard guard(GetLock());
|
||||
|
||||
if (bindings.empty())
|
||||
return;
|
||||
|
||||
auto result = bindings.find(key);
|
||||
if (result == bindings.end())
|
||||
return;
|
||||
|
||||
BindingList& list = result->second;
|
||||
for (auto i = list.begin(); i != list.end();)
|
||||
{
|
||||
std::unique_ptr<Binding>& binding = (*i);
|
||||
auto i_prev = (i++);
|
||||
|
||||
lua_rawgeti(L, LUA_REGISTRYINDEX, binding->functionReference);
|
||||
|
||||
if (binding->remainingShots > 0)
|
||||
{
|
||||
binding->remainingShots -= 1;
|
||||
|
||||
if (binding->remainingShots == 0)
|
||||
{
|
||||
id_lookup_table.erase(binding->id);
|
||||
list.erase(i_prev);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* A `BindingMap` key type for simple event ID bindings
|
||||
* (ServerEvents, GuildEvents, etc.).
|
||||
*/
|
||||
template <typename T>
|
||||
struct EventKey
|
||||
{
|
||||
T event_id;
|
||||
|
||||
EventKey(T event_id) :
|
||||
event_id(event_id)
|
||||
{ }
|
||||
};
|
||||
|
||||
/*
|
||||
* A `BindingMap` key type for event ID/Object entry ID bindings
|
||||
* (CreatureEvents, GameObjectEvents, etc.).
|
||||
*/
|
||||
template <typename T>
|
||||
struct EntryKey
|
||||
{
|
||||
T event_id;
|
||||
uint32 entry;
|
||||
|
||||
EntryKey(T event_id, uint32 entry) :
|
||||
event_id(event_id),
|
||||
entry(entry)
|
||||
{ }
|
||||
};
|
||||
|
||||
/*
|
||||
* A `BindingMap` key type for event ID/unique Object bindings
|
||||
* (currently just CreatureEvents).
|
||||
*/
|
||||
template <typename T>
|
||||
struct UniqueObjectKey
|
||||
{
|
||||
T event_id;
|
||||
ObjectGuid guid;
|
||||
uint32 instance_id;
|
||||
|
||||
UniqueObjectKey(T event_id, ObjectGuid guid, uint32 instance_id) :
|
||||
event_id(event_id),
|
||||
guid(guid),
|
||||
instance_id(instance_id)
|
||||
{ }
|
||||
};
|
||||
|
||||
class hash_helper
|
||||
{
|
||||
public:
|
||||
typedef std::size_t result_type;
|
||||
|
||||
template <typename T1, typename T2, typename... T>
|
||||
static inline result_type hash(T1 const & t1, T2 const & t2, T const &... t)
|
||||
{
|
||||
result_type seed = 0;
|
||||
_hash_combine(seed, t1, t2, t...);
|
||||
return seed;
|
||||
}
|
||||
|
||||
template <typename T, typename std::enable_if<std::is_enum<T>::value>::type* = nullptr>
|
||||
static inline result_type hash(T const & t)
|
||||
{
|
||||
return std::hash<typename std::underlying_type<T>::type>()(t);
|
||||
}
|
||||
|
||||
template <typename T, typename std::enable_if<!std::is_enum<T>::value>::type* = nullptr>
|
||||
static inline result_type hash(T const & t)
|
||||
{
|
||||
return std::hash<T>()(t);
|
||||
}
|
||||
|
||||
private:
|
||||
template <typename T>
|
||||
static inline void _hash_combine(result_type& seed, T const & v)
|
||||
{
|
||||
// from http://www.boost.org/doc/libs/1_40_0/boost/functional/hash/hash.hpp
|
||||
seed ^= hash(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
|
||||
}
|
||||
|
||||
template <typename H, typename T1, typename... T>
|
||||
static inline void _hash_combine(result_type& seed, H const & h, T1 const & t1, T const &... t)
|
||||
{
|
||||
_hash_combine(seed, h);
|
||||
_hash_combine(seed, t1, t...);
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* Implementations of various std functions on the above key types,
|
||||
* so that they can be used within an unordered_map.
|
||||
*/
|
||||
namespace std
|
||||
{
|
||||
template<typename T>
|
||||
struct equal_to < EventKey<T> >
|
||||
{
|
||||
bool operator()(EventKey<T> const& lhs, EventKey<T> const& rhs) const
|
||||
{
|
||||
return lhs.event_id == rhs.event_id;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct equal_to < EntryKey<T> >
|
||||
{
|
||||
bool operator()(EntryKey<T> const& lhs, EntryKey<T> const& rhs) const
|
||||
{
|
||||
return lhs.event_id == rhs.event_id
|
||||
&& lhs.entry == rhs.entry;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct equal_to < UniqueObjectKey<T> >
|
||||
{
|
||||
bool operator()(UniqueObjectKey<T> const& lhs, UniqueObjectKey<T> const& rhs) const
|
||||
{
|
||||
return lhs.event_id == rhs.event_id
|
||||
&& lhs.guid == rhs.guid
|
||||
&& lhs.instance_id == rhs.instance_id;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct hash < EventKey<T> >
|
||||
{
|
||||
typedef EventKey<T> argument_type;
|
||||
|
||||
hash_helper::result_type operator()(argument_type const& k) const
|
||||
{
|
||||
return hash_helper::hash(k.event_id);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct hash < EntryKey<T> >
|
||||
{
|
||||
typedef EntryKey<T> argument_type;
|
||||
|
||||
hash_helper::result_type operator()(argument_type const& k) const
|
||||
{
|
||||
return hash_helper::hash(k.event_id, k.entry);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct hash < UniqueObjectKey<T> >
|
||||
{
|
||||
typedef UniqueObjectKey<T> argument_type;
|
||||
|
||||
hash_helper::result_type operator()(argument_type const& k) const
|
||||
{
|
||||
return hash_helper::hash(k.event_id, k.instance_id, k.guid.GetRawValue());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif // _BINDING_MAP_H
|
||||
Reference in New Issue
Block a user