Skip to content

Commit 73c1050

Browse files
committed
Implement ScriptEntity
1 parent bb0548c commit 73c1050

File tree

2 files changed

+37
-8
lines changed

2 files changed

+37
-8
lines changed

source/extensions/utility.hpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -446,4 +446,13 @@ F step_to(F x, F to, F step, bool useTimeStep = false) {
446446
//! See: https://stackoverflow.com/a/64228354/15363969
447447
template <typename R, typename T>
448448
concept range_of = rng::range<R> && std::same_as<rng::range_value_t<R>, T>;
449+
450+
// https://www.reddit.com/r/cpp/comments/1hw6a29/comment/m61d6wv
451+
template <class T, template <typename...> class Template>
452+
concept is_specialization_of = requires ( std::remove_cvref_t<T> t )
453+
{
454+
// Check an immediately invoked lambda can compile
455+
[]<typename... Args> ( Template<Args...>& ) {} ( t );
449456
};
457+
458+
}; // namespace notsa

source/game_sa/Scripts/CommandParser/ReadArg.hpp

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,17 @@ template<typename Base, typename Derived>
100100
constexpr 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)
104115
template<typename T>
105116
inline 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

Comments
 (0)