diff --git a/include/Common.hh b/include/Common.hh index 932505ee..84350f40 100644 --- a/include/Common.hh +++ b/include/Common.hh @@ -3,27 +3,13 @@ #pragma once -#include +#include #include #include -#include #include -typedef int8_t s8; -typedef int16_t s16; -typedef int32_t s32; -typedef int64_t s64; - -typedef uint8_t u8; -typedef uint16_t u16; -typedef uint32_t u32; -typedef uint64_t u64; - -typedef float f32; -typedef double f64; - enum class Course { Mario_Circuit = 0, Moo_Moo_Meadows = 1, diff --git a/include/Types.hh b/include/Types.hh new file mode 100644 index 00000000..3a0e2b2c --- /dev/null +++ b/include/Types.hh @@ -0,0 +1,187 @@ +#pragma once + +#include + +#include +#include + +typedef int8_t s8; +typedef int16_t s16; +typedef int32_t s32; +typedef int64_t s64; + +typedef uint8_t u8; +typedef uint16_t u16; +typedef uint32_t u32; +typedef uint64_t u64; + +typedef float f32; +typedef double f64; + +/// @brief Dynamically sized array that only allocates once. +/// @details It's possible that only an upper bound is known for a given vector. +/// However, in the event that there are more objects than expected, we want to error. +/// @tparam T The type of objects in the array. +template +class fixed_vector { +public: + /// @brief Non-initializing constructor. + fixed_vector() : m_data(nullptr), m_size(0), m_capacity(0) {} + + /// @brief Initializing constructor. + /// @param capacity The number of elements to initialize the vector with. + fixed_vector(size_t capacity) : fixed_vector() { + allocate(capacity); + } + + /// @brief Destructor. + /// @details Destroys all existing elements in the array in-place from the end to the start. + ~fixed_vector() { + while (m_size > 0) { + pop_back(); + } + + operator delete(m_data); + } + + /// @brief Copies a new element into the array. + /// @param obj The object to copy. + /// @return A reference to the object. + T &push_back(const T &obj) { + ASSERT(initialized() && !full()); + new (m_data + m_size++) T(obj); + return back(); + } + + /// @brief Moves a new element into the array. + /// @param obj The object to move. + /// @return A reference to the object. + T &push_back(T &&obj) { + ASSERT(initialized() && !full()); + new (m_data + m_size++) T(std::move(obj)); + return back(); + } + + /// @brief Creates a new element in-place in the array. + /// @tparam ...Args Variadic template for packing. + /// @param ...args Arguments to the constructor. + /// @return A reference to the object. + template + T &emplace_back(Args &&...args) { + ASSERT(initialized() && !full()); + new (m_data + m_size++) T(std::forward(args)...); + return back(); + } + + /// @brief Deletes the last existing element from the array. + void pop_back() { + ASSERT(initialized() && !empty()); + m_data[--m_size].~T(); + } + + /// @brief Initializes the vector with the provided capacity. + /// @param capacity The number of elements to initialize the vector with. + void reserve(size_t capacity) { + ASSERT(!initialized()); + allocate(capacity); + } + + /// @brief Checks if there are no existing elements in the array. + /// @return True if the array is empty, otherwise false. + bool empty() const { + return m_size == 0; + } + + /// @brief Checks if all elements exist in the array. + /// @return True if the array is full, otherwise false. + bool full() const { + return m_size == m_capacity; + } + + /// @brief Checks if the array exists and if the capacity is non-zero. + /// @return True if the array is initialized, otherwise false. + bool initialized() const { + return m_data && m_capacity != 0; + } + + /// @brief Gets the first element in the array, whether it exists or not. + /// @return The first element in the array. + T &front() { + return *m_data; + } + + /// @brief Gets the first element in the array, whether it exists or not. + /// @return The first element in the array. + const T &front() const { + return *m_data; + } + + /// @brief Gets the last existing element in the array, or the first element if none exist. + /// @return The last existing element in the array. + T &back() { + return *(m_data + m_size); + } + + /// @brief Gets the last existing element in the array, or the first element if none exist. + /// @return The last existing element in the array. + const T &back() const { + return *(m_data + m_size); + } + + /// @brief Indexes the array. Validates that the object exists. + /// @param idx The index to the array. + /// @return A reference to the object at the corresponding index. + T &operator[](size_t idx) { + ASSERT(idx < m_size); + return m_data[idx]; + } + + /// @brief Indexes the array. Validates that the object exists. + /// @param idx The index to the array. + /// @return A reference to the object at the corresponding index. + const T &operator[](size_t idx) const { + ASSERT(idx < m_size); + return m_data[idx]; + } + + /// @brief Iterator for the beginning of the existing array. + /// @return Iterator. + T *begin() noexcept { + ASSERT(initialized()); + return m_data; + } + + /// @brief Iterator for the beginning of the existing array. + /// @return Const iterator. + const T *begin() const noexcept { + ASSERT(initialized()); + return m_data; + } + + /// @brief Iterator for the end of the existing array. + /// @return Iterator. + T *end() noexcept { + ASSERT(initialized()); + return m_data + m_size; + } + + /// @brief Iterator for the end of the existing array. + /// @return Const iterator. + const T *end() const noexcept { + ASSERT(initialized()); + return m_data + m_size; + } + +private: + /// @brief Allocates the array. + /// @param capacity The number of elements to initialize the vector with. + void allocate(size_t capacity) { + ASSERT(!initialized()); + m_data = reinterpret_cast(operator new(sizeof(T) * capacity)); + m_capacity = capacity; + } + + T *m_data; // The underlying array pointer. + size_t m_size; // The number of existing elements in the array. + size_t m_capacity; // The maximum number of elements that can exist in the array. +}; diff --git a/source/game/field/ObjectDirector.cc b/source/game/field/ObjectDirector.cc index 7b3c10ef..be47ac70 100644 --- a/source/game/field/ObjectDirector.cc +++ b/source/game/field/ObjectDirector.cc @@ -138,7 +138,8 @@ ObjectDirector *ObjectDirector::Instance() { /// @addr{0x8082A38C} ObjectDirector::ObjectDirector() : m_flowTable("ObjFlow.bin"), m_hitTableKart("GeoHitTableKart.bin"), - m_hitTableKartObject("GeoHitTableKartObj.bin") {} + m_hitTableKartObject("GeoHitTableKartObj.bin"), m_objects(MAX_UNIT_COUNT), + m_calcObjects(MAX_UNIT_COUNT), m_collisionObjects(MAX_UNIT_COUNT) {} /// @addr{0x8082A694} ObjectDirector::~ObjectDirector() { @@ -157,13 +158,6 @@ void ObjectDirector::createObjects() { const auto *courseMap = System::CourseMap::Instance(); size_t objectCount = courseMap->getGeoObjCount(); - // It's possible for the KMP to specify settings for objects that aren't tracked here - // MAX_UNIT_COUNT is the upper bound for tracked object count, so we reserve the minimum - size_t maxCount = std::min(objectCount, MAX_UNIT_COUNT); - m_objects.reserve(maxCount); - m_calcObjects.reserve(maxCount); - m_collisionObjects.reserve(maxCount); - for (size_t i = 0; i < objectCount; ++i) { const auto *pObj = courseMap->getGeoObj(i); ASSERT(pObj); diff --git a/source/game/field/ObjectDirector.hh b/source/game/field/ObjectDirector.hh index ae037384..aacb0f27 100644 --- a/source/game/field/ObjectDirector.hh +++ b/source/game/field/ObjectDirector.hh @@ -5,8 +5,6 @@ #include "game/field/ObjectHitTable.hh" #include "game/field/obj/ObjectCollidable.hh" -#include - namespace Field { class ObjectDirector : EGG::Disposer { @@ -38,9 +36,9 @@ private: ObjectHitTable m_hitTableKart; ObjectHitTable m_hitTableKartObject; - std::vector m_objects; ///< All objects live here - std::vector m_calcObjects; ///< Objects needing calc() live here too. - std::vector m_collisionObjects; ///< Objects having collision live here too + fixed_vector m_objects; ///< All objects live here + fixed_vector m_calcObjects; ///< Objects needing calc() live here too. + fixed_vector m_collisionObjects; ///< Objects having collision live here too static constexpr size_t MAX_UNIT_COUNT = 0x100; diff --git a/source/game/kart/KartMove.cc b/source/game/kart/KartMove.cc index a5459ba5..ef2cb363 100644 --- a/source/game/kart/KartMove.cc +++ b/source/game/kart/KartMove.cc @@ -1253,18 +1253,14 @@ f32 KartMove::calcVehicleAcceleration() const { return 1.0f; } - std::vector as; - std::vector ts; + std::span as; + std::span ts; if (state()->isDrifting()) { - const auto &as_arr = param()->stats().accelerationDriftA; - const auto &ts_arr = param()->stats().accelerationDriftT; - as = {as_arr.begin(), as_arr.end()}; - ts = {ts_arr.begin(), ts_arr.end()}; + as = param()->stats().accelerationDriftA; + ts = param()->stats().accelerationDriftT; } else { - const auto &as_arr = param()->stats().accelerationStandardA; - const auto &ts_arr = param()->stats().accelerationStandardT; - as = {as_arr.begin(), as_arr.end()}; - ts = {ts_arr.begin(), ts_arr.end()}; + as = param()->stats().accelerationStandardA; + ts = param()->stats().accelerationStandardT; } size_t i = 0; diff --git a/source/game/kart/KartObject.cc b/source/game/kart/KartObject.cc index 8a5083dc..58757c4c 100644 --- a/source/game/kart/KartObject.cc +++ b/source/game/kart/KartObject.cc @@ -134,6 +134,9 @@ void KartObject::prepareTiresAndSuspensions() { m_pointers.param->setTireCount(wheelCount); m_pointers.param->setSuspCount(wheelCount); + + m_pointers.tires.reserve(wheelCount); + m_pointers.suspensions.reserve(wheelCount); } /// @addr{0x8058E724} diff --git a/source/game/kart/KartObjectProxy.hh b/source/game/kart/KartObjectProxy.hh index de5d8b10..d893a7cc 100644 --- a/source/game/kart/KartObjectProxy.hh +++ b/source/game/kart/KartObjectProxy.hh @@ -5,7 +5,6 @@ #include #include -#include namespace Field { @@ -51,8 +50,8 @@ struct KartAccessor { Field::ObjectCollisionKart *objectCollisionKart; KartState *state; - std::vector suspensions; - std::vector tires; + fixed_vector suspensions; + fixed_vector tires; Field::BoxColUnit *boxColUnit; };