Core/Objects: Implement SetUpdateField

This commit is contained in:
Shauren
2026-01-25 22:26:07 +01:00
parent 8e4635ffe2
commit 0168e1b04a
3 changed files with 243 additions and 20 deletions

View File

@@ -127,15 +127,27 @@ namespace UF
}
template<typename K, typename V>
inline void RemoveMapUpdateFieldValue(MapUpdateFieldSetter<K, V>& setter, std::type_identity_t<K> const& key)
inline bool RemoveMapUpdateFieldValue(MapUpdateFieldSetter<K, V>& setter, std::type_identity_t<K> const& key)
{
setter.RemoveKey(key);
return setter.RemoveKey(key);
}
template<typename T>
inline void RemoveOptionalUpdateFieldValue(OptionalUpdateFieldSetter<T>& setter)
inline bool InsertSetUpdateFieldValue(SetUpdateFieldSetter<T>& setter, std::type_identity_t<T> const& key)
{
setter.RemoveValue();
return setter.Insert(key);
}
template<typename T>
inline bool RemoveSetUpdateFieldValue(SetUpdateFieldSetter<T>& setter, std::type_identity_t<T> const& key)
{
return setter.Remove(key);
}
template<typename T>
inline bool RemoveOptionalUpdateFieldValue(OptionalUpdateFieldSetter<T>& setter)
{
return setter.RemoveValue();
}
}
@@ -250,13 +262,6 @@ class TC_GAME_API BaseEntity
UF::RemoveDynamicUpdateFieldValue(setter, index);
}
template<typename K, typename V>
void RemoveMapUpdateFieldValue(UF::MapUpdateFieldSetter<K, V> setter, std::type_identity_t<K> const& key)
{
AddToObjectUpdateIfNeeded();
UF::RemoveMapUpdateFieldValue(setter, key);
}
template<typename T>
void ClearDynamicUpdateFieldValues(UF::DynamicUpdateFieldSetter<T> setter)
{
@@ -264,11 +269,32 @@ class TC_GAME_API BaseEntity
UF::ClearDynamicUpdateFieldValues(setter);
}
template<typename K, typename V>
void RemoveMapUpdateFieldValue(UF::MapUpdateFieldSetter<K, V> setter, std::type_identity_t<K> const& key)
{
if (UF::RemoveMapUpdateFieldValue(setter, key))
AddToObjectUpdateIfNeeded();
}
template<typename T>
void InsertSetUpdateFieldValue(UF::SetUpdateFieldSetter<T> setter, std::type_identity_t<T> const& key)
{
if (UF::InsertSetUpdateFieldValue(setter, key))
AddToObjectUpdateIfNeeded();
}
template<typename T>
void RemoveSetUpdateFieldValue(UF::SetUpdateFieldSetter<T> setter, std::type_identity_t<T> const& key)
{
if (UF::RemoveSetUpdateFieldValue(setter, key))
AddToObjectUpdateIfNeeded();
}
template<typename T>
void RemoveOptionalUpdateFieldValue(UF::OptionalUpdateFieldSetter<T> setter)
{
AddToObjectUpdateIfNeeded();
UF::RemoveOptionalUpdateFieldValue(setter);
if (UF::RemoveOptionalUpdateFieldValue(setter))
AddToObjectUpdateIfNeeded();
}
// stat system helpers

View File

@@ -71,6 +71,12 @@ namespace UF
template<typename K, typename V, int32 BlockBit, uint32 Bit>
class MapUpdateField;
template<typename T>
class SetUpdateFieldBase;
template<typename T, int32 BlockBit, uint32 Bit>
class SetUpdateField;
template<typename T>
class OptionalUpdateFieldBase;
@@ -260,34 +266,70 @@ namespace UF
struct MapUpdateFieldSetter
{
template<typename F, typename G>
friend void RemoveMapUpdateFieldValue(MapUpdateFieldSetter<F, G>& setter, std::type_identity_t<F> const& key);
friend bool RemoveMapUpdateFieldValue(MapUpdateFieldSetter<F, G>& setter, std::type_identity_t<F> const& key);
MapUpdateFieldSetter(std::unordered_map<K, V>& values) : _values(values) { }
private:
void RemoveKey(K const& key)
bool RemoveKey(K const& key)
{
auto itr = _values.find(key);
if (itr != _values.end())
{
itr->second.state = MapUpdateFieldState::Deleted;
return true;
}
return false;
}
std::unordered_map<K, V>& _values;
};
template<typename T>
struct SetUpdateFieldSetter
{
template<typename F>
friend bool RemoveSetUpdateFieldValue(SetUpdateFieldSetter<F>& setter, std::type_identity_t<F> const& key);
SetUpdateFieldSetter(std::unordered_map<T, MapUpdateFieldState>& values) : _values(values) { }
private:
bool Insert(T const& key)
{
return _values.emplace(key, MapUpdateFieldState::Changed).second;
}
bool Remove(T const& key)
{
auto itr = _values.find(key);
if (itr != _values.end())
{
itr->second = MapUpdateFieldState::Deleted;
return true;
}
return false;
}
std::unordered_map<T, MapUpdateFieldState>& _values;
};
template<typename T>
struct OptionalUpdateFieldSetter
{
template<typename F>
friend void RemoveOptionalUpdateFieldValue(OptionalUpdateFieldSetter<F>& setter);
friend bool RemoveOptionalUpdateFieldValue(OptionalUpdateFieldSetter<F>& setter);
OptionalUpdateFieldSetter(OptionalUpdateFieldBase<T>& field) : _field(field) { }
private:
void RemoveValue()
bool RemoveValue()
{
if (_field.has_value())
{
_field.DestroyValue();
return true;
}
return false;
}
OptionalUpdateFieldBase<T>& _field;
@@ -397,6 +439,16 @@ namespace UF
return { itr->second.value };
}
template<typename V, int32 BlockBit, uint32 Bit>
SetUpdateFieldSetter<V> ModifyValue(SetUpdateField<V, BlockBit, Bit>(T::* field))
{
if constexpr (BlockBit >= 0)
_value._changesMask.Set(BlockBit);
_value._changesMask.Set(Bit);
return { (_value.*field)._values };
}
template<typename V, int32 BlockBit, uint32 Bit>
OptionalUpdateFieldSetter<V> ModifyValue(OptionalUpdateField<V, BlockBit, Bit>(T::* field))
{
@@ -639,6 +691,21 @@ namespace UF
itr->second.state = MapUpdateFieldState::Changed;
}
template<typename Derived, typename T, int32 BlockBit, uint32 Bit>
void MarkChanged(SetUpdateField<T, BlockBit, Bit>(Derived::* field), std::type_identity_t<T> const& key)
{
static_assert(std::is_base_of_v<Base, Derived>, "Given field argument must belong to the same structure as this HasChangesMask");
if constexpr (BlockBit >= 0)
_changesMask.Set(BlockBit);
_changesMask.Set(Bit);
SetUpdateField<T, BlockBit, Bit>& uf = (static_cast<Derived*>(this)->*field);
auto itr = uf._values.find(key);
if (itr != uf._values.end() && itr->second == MapUpdateFieldState::Unchanged)
itr->second = MapUpdateFieldState::Changed;
}
template<typename Derived, typename T, int32 BlockBit, uint32 Bit>
void MarkChanged(OptionalUpdateField<T, BlockBit, Bit>(Derived::*))
{
@@ -704,6 +771,17 @@ namespace UF
itr->second.state = MapUpdateFieldState::Unchanged;
}
template<typename Derived, typename T, int32 BlockBit, uint32 Bit>
void ClearChanged(SetUpdateField<T, BlockBit, Bit>(Derived::* field), std::type_identity_t<T> const& key)
{
static_assert(std::is_base_of_v<Base, Derived>, "Given field argument must belong to the same structure as this HasChangesMask");
SetUpdateField<T, BlockBit, Bit>& uf = (static_cast<Derived*>(this)->*field);
auto itr = uf._values.find(key);
if (itr != uf._values.end() && itr->second == MapUpdateFieldState::Changed)
itr->second = MapUpdateFieldState::Unchanged;
}
template<typename Derived, typename T, int32 BlockBit, uint32 Bit>
void ClearChanged(OptionalUpdateField<T, BlockBit, Bit>(Derived::*))
{
@@ -759,7 +837,7 @@ namespace UF
break;
case MapUpdateFieldState::Changed:
if constexpr (std::is_base_of_v<HasChangesMaskTag, K>)
itr->first.ClearChangesMask();
const_cast<K&>(itr->first).ClearChangesMask();
if constexpr (std::is_base_of_v<HasChangesMaskTag, V>)
itr->second.value.ClearChangesMask();
@@ -777,6 +855,32 @@ namespace UF
}
}
template<typename T>
static inline void ClearChangesMask(SetUpdateFieldBase<T>& field)
{
for (auto itr = field._values.begin(); itr != field._values.end(); )
{
switch (itr->second)
{
case MapUpdateFieldState::Unchanged:
break;
case MapUpdateFieldState::Changed:
if constexpr (std::is_base_of_v<HasChangesMaskTag, T>)
const_cast<T&>(itr->first).ClearChangesMask();
itr->second = MapUpdateFieldState::Unchanged;
break;
case MapUpdateFieldState::Deleted:
itr = field._values.erase(itr++);
continue;
default:
break;
}
++itr;
}
}
template<typename T>
static inline void ClearChangesMask(OptionalUpdateFieldBase<T>& field)
{
@@ -1085,6 +1189,55 @@ namespace UF
{
};
template<typename T>
class SetUpdateFieldBase : public IsUpdateFieldHolderTag
{
template<typename F, bool PublicSet>
friend struct MutableFieldReferenceWithChangesMask;
template<typename F, bool PublicSet>
friend struct MutableFieldReferenceNoChangesMask;
template<typename F, bool PublicSet>
friend struct MutableNestedFieldReference;
template<std::size_t Bits>
friend class HasChangesMask;
public:
using key_type = T;
using mapped_type = MapUpdateFieldState;
using value_type = std::pair<key_type const, mapped_type>;
typename std::unordered_map<T, MapUpdateFieldState>::const_iterator begin() const
{
return _values.begin();
}
typename std::unordered_map<T, MapUpdateFieldState>::const_iterator end() const
{
return _values.end();
}
bool empty() const
{
return _values.empty();
}
std::size_t size() const
{
return _values.size();
}
private:
std::unordered_map<T, MapUpdateFieldState> _values;
};
template<typename T, int32 BlockBit, uint32 Bit>
class SetUpdateField : public SetUpdateFieldBase<T>
{
};
template<typename T>
class OptionalUpdateFieldBase : public IsUpdateFieldHolderTag
{

View File

@@ -107,7 +107,7 @@ inline void WriteMapFieldUpdate(MapUpdateFieldBase<K, V> const& map, ByteBuffer&
++changesCount;
if constexpr (std::is_base_of_v<IsUpdateFieldStructureTag, K>)
k.WriteUpdate(data, true /*ignoreChangesMask*/, owner, receiver);
k.WriteUpdate(data, false, owner, receiver);
else
data << k;
@@ -116,7 +116,7 @@ inline void WriteMapFieldUpdate(MapUpdateFieldBase<K, V> const& map, ByteBuffer&
continue;
if constexpr (std::is_base_of_v<IsUpdateFieldStructureTag, V>)
v.value.WriteUpdate(data, true /*ignoreChangesMask*/, owner, receiver); // client bug replaces unchanged values with 0/default so send everything as if it changed
v.value.WriteUpdate(data, false, owner, receiver);
else
data << v.value;
}
@@ -124,6 +124,50 @@ inline void WriteMapFieldUpdate(MapUpdateFieldBase<K, V> const& map, ByteBuffer&
data.put<uint16>(changesCountPos, changesCount);
}
}
template <typename T, typename O>
inline void WriteSetFieldCreate(SetUpdateFieldBase<T> const& set, ByteBuffer& data, O const* owner, Player const* receiver)
{
data << uint32(set.size());
for (auto const& [k, _] : set)
{
if constexpr (std::is_base_of_v<IsUpdateFieldStructureTag, T>)
k.WriteCreate(data, owner, receiver);
else
data << k;
}
}
template <typename T, typename O>
inline void WriteSetFieldUpdate(SetUpdateFieldBase<T> const& set, ByteBuffer& data, bool ignoreChangesMask, O const* owner, Player const* receiver)
{
data << uint8(ignoreChangesMask ? 1 : 0);
if (ignoreChangesMask)
UF::WriteSetFieldCreate(set, data, owner, receiver);
else
{
uint16 changesCount = 0;
size_t changesCountPos = data.wpos();
data << uint16(changesCount);
for (auto const& [k, state] : set)
{
if (state == MapUpdateFieldState::Unchanged)
continue;
++changesCount;
if constexpr (std::is_base_of_v<IsUpdateFieldStructureTag, T>)
k.WriteUpdate(data, false, owner, receiver);
else
data << k;
data << uint8(state);
}
data.put<uint16>(changesCountPos, changesCount);
}
}
}
#endif // TRINITYCORE_UPDATE_FIELD_IMPL_H