@@ -100,6 +100,17 @@ template<typename Base, typename Derived>
100100constexpr auto is_derived_from_but_not_v = std::is_base_of_v<Base, Derived> && !std::is_same_v<Base, Derived>;
101101};
102102
103+ // ! Script entity (Not necessarily a derivative of `CEntity`, but any pooled type)
104+ template <typename T>
105+ struct ScriptEntity {
106+ static_assert (!std::is_pointer_v<T> && !std::is_reference_v<T>, " T must be a class type, not a pointer or reference." );
107+
108+ using EntityType = T;
109+
110+ EntityType* e; // /< Pointer to the actual entity (May be null if the handle is invalid)
111+ int32 h; // /< Script handle of the entity
112+ };
113+
103114// ! Read a value (Possibly from script => increases IP, or return a value (w/o increasing IP)
104115template <typename T>
105116inline T Read (CRunningScript* S) {
@@ -209,20 +220,29 @@ inline T Read(CRunningScript* S) {
209220 return static_cast <Y>(Read<std::underlying_type_t <Y>>(S));
210221 } else if constexpr (std::is_same_v<Y, CPlayerPed>) { // Special case for `CPlayerPed` (As the IDs for it aren't from the pool)
211222 return FindPlayerPed (Read<int32>(S));
212- } else if constexpr (detail::PooledType<Y>) { // Pooled types (CVehicle, CPed, etc)
213- T ptr = static_cast <T>(detail::PoolOf<Y>().GetAtRef (Read<int32>(S)));
223+ } else if constexpr (notsa::is_specialization_of<Y, ScriptEntity>) {
224+ using EntityType = typename Y::EntityType;
225+
226+ const auto handle = Read<int32>(S);
227+ auto entity = static_cast <EntityType*>(detail::PoolOf<EntityType>().GetAtRef (handle));
214228
215229 #ifdef NOTSA_DEBUG
216- if (ptr) {
217- if constexpr (detail::is_derived_from_but_not_v<CVehicle, Y>) {
218- assert (Y::Type == ptr->m_nVehicleSubType ); // check specialized type, in case of e.g. CAutomobile and one of its derived classes: CPlane, CHeli, etc
219- } else if constexpr (detail::is_derived_from_but_not_v<CTask, Y>) {
220- assert (Y::Type == ptr->GetTaskType ());
230+ // Asserts for correct type
231+ if (entity) {
232+ if constexpr (detail::is_derived_from_but_not_v<CVehicle, EntityType>) {
233+ assert (EntityType::Type == entity->m_nVehicleSubType ); // check specialized type, in case of e.g. CAutomobile and one of its derived classes: CPlane, CHeli, etc
234+ } else if constexpr (detail::is_derived_from_but_not_v<CTask, EntityType>) {
235+ assert (EntityType::Type == entity->GetTaskType ());
221236 } // TODO: Eventually add this for `CEvent` too
222237 }
223238 #endif
224239
225- return ptr;
240+ return {
241+ .e = entity,
242+ .h = handle
243+ };
244+ } else if constexpr (detail::PooledType<Y>) { // Pooled types (CVehicle, CPed, etc)
245+ return Read<ScriptEntity<Y>>(S).e ;
226246 } else if constexpr (std::is_same_v<Y, CRunningScript>) { // Just return the script from where this command was invoked from
227247 return S;
228248 } else if constexpr (std::is_same_v<Y, CPlayerInfo>) {
0 commit comments