`ScriptEntity` - Wrapper for an entity + it's handle (#1137)

* fix: Fix incorrect check in `AddCollisionSoundToList`
* Implement `ScriptEntity`

---------

Co-authored-by: Seemann <x87@users.noreply.github.com>
This commit is contained in:
Pirulax 2025-12-13 13:57:13 +01:00 committed by GitHub
parent 8da8f88717
commit f1fc49a209
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 37 additions and 8 deletions

View File

@ -446,4 +446,13 @@ F step_to(F x, F to, F step, bool useTimeStep = false) {
//! See: https://stackoverflow.com/a/64228354/15363969 //! See: https://stackoverflow.com/a/64228354/15363969
template <typename R, typename T> template <typename R, typename T>
concept range_of = rng::range<R> && std::same_as<rng::range_value_t<R>, T>; concept range_of = rng::range<R> && std::same_as<rng::range_value_t<R>, T>;
// https://www.reddit.com/r/cpp/comments/1hw6a29/comment/m61d6wv
template <class T, template <typename...> class Template>
concept is_specialization_of = requires ( std::remove_cvref_t<T> t )
{
// Check an immediately invoked lambda can compile
[]<typename... Args> ( Template<Args...>& ) {} ( t );
}; };
}; // namespace notsa

View File

@ -100,6 +100,17 @@ template<typename Base, typename Derived>
constexpr auto is_derived_from_but_not_v = std::is_base_of_v<Base, Derived> && !std::is_same_v<Base, Derived>; constexpr auto is_derived_from_but_not_v = std::is_base_of_v<Base, Derived> && !std::is_same_v<Base, Derived>;
}; };
//! Script entity (Not necessarily a derivative of `CEntity`, but any pooled type)
template<typename T>
struct ScriptEntity {
static_assert(!std::is_pointer_v<T> && !std::is_reference_v<T>, "T must be a class type, not a pointer or reference.");
using EntityType = T;
EntityType* e; ///< Pointer to the actual entity (May be null if the handle is invalid)
int32 h; ///< Script handle of the entity
};
//! Read a value (Possibly from script => increases IP, or return a value (w/o increasing IP) //! Read a value (Possibly from script => increases IP, or return a value (w/o increasing IP)
template<typename T> template<typename T>
inline T Read(CRunningScript* S) { inline T Read(CRunningScript* S) {
@ -209,20 +220,29 @@ inline T Read(CRunningScript* S) {
return static_cast<Y>(Read<std::underlying_type_t<Y>>(S)); return static_cast<Y>(Read<std::underlying_type_t<Y>>(S));
} else if constexpr (std::is_same_v<Y, CPlayerPed>) { // Special case for `CPlayerPed` (As the IDs for it aren't from the pool) } else if constexpr (std::is_same_v<Y, CPlayerPed>) { // Special case for `CPlayerPed` (As the IDs for it aren't from the pool)
return FindPlayerPed(Read<int32>(S)); return FindPlayerPed(Read<int32>(S));
} else if constexpr (detail::PooledType<Y>) { // Pooled types (CVehicle, CPed, etc) } else if constexpr (notsa::is_specialization_of<Y, ScriptEntity>) {
T ptr = static_cast<T>(detail::PoolOf<Y>().GetAtRef(Read<int32>(S))); using EntityType = typename Y::EntityType;
const auto handle = Read<int32>(S);
auto entity = static_cast<EntityType*>(detail::PoolOf<EntityType>().GetAtRef(handle));
#ifdef NOTSA_DEBUG #ifdef NOTSA_DEBUG
if (ptr) { // Asserts for correct type
if constexpr (detail::is_derived_from_but_not_v<CVehicle, Y>) { if (entity) {
assert(Y::Type == ptr->m_nVehicleSubType); // check specialized type, in case of e.g. CAutomobile and one of its derived classes: CPlane, CHeli, etc if constexpr (detail::is_derived_from_but_not_v<CVehicle, EntityType>) {
} else if constexpr (detail::is_derived_from_but_not_v<CTask, Y>) { assert(EntityType::Type == entity->m_nVehicleSubType); // check specialized type, in case of e.g. CAutomobile and one of its derived classes: CPlane, CHeli, etc
assert(Y::Type == ptr->GetTaskType()); } else if constexpr (detail::is_derived_from_but_not_v<CTask, EntityType>) {
assert(EntityType::Type == entity->GetTaskType());
} // TODO: Eventually add this for `CEvent` too } // TODO: Eventually add this for `CEvent` too
} }
#endif #endif
return ptr; return {
.e = entity,
.h = handle
};
} else if constexpr (detail::PooledType<Y>) { // Pooled types (CVehicle, CPed, etc)
return Read<ScriptEntity<Y>>(S).e;
} else if constexpr (std::is_same_v<Y, CRunningScript>) { // Just return the script from where this command was invoked from } else if constexpr (std::is_same_v<Y, CRunningScript>) { // Just return the script from where this command was invoked from
return S; return S;
} else if constexpr (std::is_same_v<Y, CPlayerInfo>) { } else if constexpr (std::is_same_v<Y, CPlayerInfo>) {