Use enum for segnum_t

Add checked conversions for sites which load from external integers.
This commit is contained in:
Kp 2022-07-02 18:10:45 +00:00
parent fca59adb53
commit e25b476de7
30 changed files with 287 additions and 124 deletions

View file

@ -457,7 +457,6 @@ void editor_status( const char *text);
extern int MacroNumEvents;
extern int MacroStatus;
//extern int Highest_segment_index; // Highest index in Segments, an efficiency hack
extern int Lock_view_to_cursegp; // !0 means whenever cursegp changes, view it
// eglobal.c

View file

@ -115,8 +115,21 @@ protected:
static inline index_type check_index_range_size(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_DEFN_VARS std::size_t, const array_managed_type *);
template <typename handle_index_mismatch, typename handle_index_range_error>
static inline void check_explicit_index_range_ref(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_DEFN_VARS const_reference_type, std::size_t, const array_managed_type &);
/* Given a reference `r` to an element that should be in the array `a`,
* compute the array index `i` that should refer to `r`. Check that `i` is
* within the bounds of the array, and that computing `&a[i]` yields `&r`.
* The second test catches an error of the form:
*
* T a[3];
* T *b = reinterpret_cast<char *>(&a[1]) + 1;
* check_implicit_index_range_ref(*b, a);
*
* Use of the cast would allow the pointer to become misaligned and point
* into the middle of an instance. Such a pointer would never be correct,
* so detect and trap it here.
*/
template <typename handle_index_mismatch, typename handle_index_range_error>
static inline void check_implicit_index_range_ref(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_DEFN_VARS const_reference_type, const array_managed_type &);
static inline void check_implicit_index_range_ref(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_DEFN_VARS const_reference_type r, const array_managed_type &a);
template <typename handle_null_pointer>
static inline void check_null_pointer_conversion(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_DEFN_VARS const_pointer_type);
template <typename handle_null_pointer>

View file

@ -293,6 +293,44 @@ template <typename range_exception, std::size_t required_buffer_size, typename P
void check_range_object_size(const char *, unsigned, const char *, const P &&, std::size_t, std::size_t) {}
#endif
template <typename range_type, typename index_type>
std::true_type check_range_index_type_vs_provided_index_type(...);
template <
typename range_type,
typename provided_index_type,
/* If `range_type::index_type` is not defined, fail.
* If `range_type::index_type` is void, fail.
*/
typename range_index_type = typename std::remove_reference<typename std::remove_reference<range_type>::type::index_type &>::type
>
std::is_same<provided_index_type, range_index_type> check_range_index_type_vs_provided_index_type(std::nullptr_t);
template <typename range_type, typename index_type>
typename std::enable_if<std::is_enum<index_type>::value, std::size_t>::type cast_index_to_size(const index_type i)
{
static_assert(std::is_unsigned<typename std::underlying_type<index_type>::type>::value, "underlying_type of index_type must be unsigned");
/* If an enumerated index type is used, require that it be the type that
* the underlying range uses.
*/
static_assert(decltype(check_range_index_type_vs_provided_index_type<range_type, index_type>(nullptr))::value);
return static_cast<std::size_t>(i);
}
template <typename range_type, typename index_type>
typename std::enable_if<std::is_integral<index_type>::value, std::size_t>::type cast_index_to_size(const index_type i)
{
static_assert(std::is_unsigned<index_type>::value, "integral index_type must be unsigned");
/* Omit enforcement of range_type::index_type vs index_type, since many
* call sites provide numeric length limits.
static_assert(decltype(check_range_index_type_vs_provided_index_type<range_type, index_type>(nullptr))::value);
*/
/* Use an implicit conversion, so that an index_type of std::size_t does
* not cause a useless cast.
*/
return i;
}
}
template <
@ -360,9 +398,6 @@ inline auto (unchecked_partial_range)(
#endif
range_type &range, const index_begin_type &index_begin, const index_end_type &index_end)
{
/* Require unsigned length */
static_assert(std::is_unsigned<index_begin_type>::value, "offset to partial_range must be unsigned");
static_assert(std::is_unsigned<index_end_type>::value, "length to partial_range must be unsigned");
static_assert(!std::is_void<reference>::value, "dereference of iterator must not be void");
return unchecked_partial_range_advance<
#ifdef DXX_HAVE_BUILTIN_OBJECT_SIZE
@ -372,7 +407,9 @@ inline auto (unchecked_partial_range)(
#ifdef DXX_HAVE_BUILTIN_OBJECT_SIZE
file, line, estr,
#endif
std::begin(range), index_begin, index_end
std::begin(range),
partial_range_detail::cast_index_to_size<range_type, index_begin_type>(index_begin),
partial_range_detail::cast_index_to_size<range_type, index_end_type>(index_end)
);
}
@ -462,19 +499,21 @@ template <
[[nodiscard]]
inline auto (partial_range)(const char *const file, const unsigned line, const char *const estr, range_type &range, const index_begin_type &index_begin, const index_end_type &index_end)
{
const auto sz_begin = partial_range_detail::cast_index_to_size<range_type, index_begin_type>(index_begin);
const auto sz_end = partial_range_detail::cast_index_to_size<range_type, index_end_type>(index_end);
partial_range_detail::check_range_bounds<
typename partial_range_t<iterator_type, decltype(partial_range_detail::range_index_type<range_type>(nullptr))>::partial_range_error,
required_buffer_size
>(file, line, estr, reinterpret_cast<uintptr_t>(std::addressof(range)), index_begin, index_end, std::size(range));
>(file, line, estr, reinterpret_cast<uintptr_t>(std::addressof(range)), sz_begin, sz_end, std::size(range));
return unchecked_partial_range<
#ifdef DXX_HAVE_BUILTIN_OBJECT_SIZE
required_buffer_size,
#endif
range_type, index_begin_type, index_end_type>(
range_type>(
#ifdef DXX_HAVE_BUILTIN_OBJECT_SIZE
file, line, estr,
#endif
range, index_begin, index_end
range, sz_begin, sz_end
);
}

View file

@ -97,6 +97,9 @@ public:
class valptridx_detail::untyped_utilities::report_error_trap_terse
{
public:
/* Accept and discard any arguments, to encourage the compiler to discard
* as dead any values that exist only as arguments to `report()`.
*/
[[noreturn]]
__attribute_cold
DXX_VALPTRIDX_WARN_CALL_NOT_OPTIMIZED_OUT
@ -114,6 +117,11 @@ public:
DXX_VALPTRIDX_WARN_CALL_NOT_OPTIMIZED_OUT
static void report(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_DEFN_VARS const void *const array, const unsigned long supplied_index, const void *const expected_pointer, const void *const actual_pointer)
{
/* Load each of the arguments into storage before executing the trap,
* so that inspection of those locations in the core dump can readily
* retrieve these values, even if the values would otherwise be unused
* and optimized out.
*/
__asm__ __volatile__("" :: DXX_VALPTRIDX_REPORT_STANDARD_ASM_LOAD_COMMA_R_VARS "rm" (array), "rm" (supplied_index), "rm" (expected_pointer), "rm" (actual_pointer));
__builtin_trap();
}
@ -259,8 +267,8 @@ template <typename managed_type>
template <typename handle_index_mismatch, typename handle_index_range_error>
void valptridx<managed_type>::check_explicit_index_range_ref(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_DEFN_VARS const_reference_type &r, std::size_t i, const array_managed_type &a)
{
check_index_match<handle_index_mismatch>(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_PASS_VARS r, i, a);
check_index_range_size<handle_index_range_error>(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_PASS_VARS i, &a);
const auto ii = check_index_range_size<handle_index_range_error>(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_PASS_VARS i, &a);
check_index_match<handle_index_mismatch>(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_PASS_VARS r, ii, a);
}
template <typename managed_type>
@ -268,7 +276,9 @@ class valptridx<managed_type>::partial_policy::require_valid
{
public:
static constexpr std::false_type allow_nullptr{};
[[nodiscard]]
static constexpr std::false_type check_allowed_invalid_index(index_type) { return {}; }
[[nodiscard]]
static constexpr bool check_nothrow_index(index_type i)
{
return std::less<std::size_t>()(static_cast<std::size_t>(i), array_size);
@ -280,10 +290,12 @@ class valptridx<managed_type>::partial_policy::allow_invalid
{
public:
static constexpr std::true_type allow_nullptr{};
[[nodiscard]]
static constexpr bool check_allowed_invalid_index(index_type i)
{
return i == static_cast<index_type>(~0);
}
[[nodiscard]]
static constexpr bool check_nothrow_index(index_type i)
{
return check_allowed_invalid_index(i) || require_valid::check_nothrow_index(i);
@ -369,11 +381,10 @@ public:
}
template <typename rpolicy, typename std::enable_if<!(policy::allow_nullptr || !rpolicy::allow_nullptr), int>::type = 0>
idx(const idx<rpolicy> &rhs DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_L_DECL_VARS) :
m_idx(rhs.get_unchecked_index())
{
/* If moving from allow_invalid to require_valid, check range.
*/
check_index_range<index_range_error_type<array_managed_type>>(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_PASS_VARS m_idx, nullptr);
m_idx(check_index_range<index_range_error_type<array_managed_type>>(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_PASS_VARS rhs.get_unchecked_index(), nullptr))
{
}
template <typename rpolicy>
idx(idx<rpolicy> &&rhs) :

View file

@ -247,7 +247,7 @@ struct ai_static_rw
{
ubyte behavior; //
int8_t flags[11]; // various flags, meaning defined by constants
short hide_segment; // Segment to go to for hiding.
uint16_t hide_segment; // Segment to go to for hiding.
short hide_index; // Index in Path_seg_points
short path_length; // Length of hide path.
#if defined(DXX_BUILD_DESCENT_I)

View file

@ -20,7 +20,7 @@
namespace dcx {
constexpr std::integral_constant<std::size_t, 9000> MAX_SEGMENTS{};
using segnum_t = uint16_t;
enum segnum_t : uint16_t;
struct d_level_unique_automap_state;
}
#ifdef dsx
@ -54,9 +54,9 @@ constexpr std::integral_constant<std::size_t, 4 * MAX_SEGMENTS> MAX_SEGMENT_VERT
#ifdef dsx
DXX_VALPTRIDX_DEFINE_SUBTYPE_TYPEDEFS(segment, seg);
static constexpr valptridx<segment>::magic_constant<0xfffe> segment_exit{};
static constexpr valptridx<segment>::magic_constant<0xffff> segment_none{};
static constexpr valptridx<segment>::magic_constant<0> segment_first{};
static constexpr valptridx<segment>::magic_constant<segnum_t{0xfffe}> segment_exit{};
static constexpr valptridx<segment>::magic_constant<segnum_t{0xffff}> segment_none{};
static constexpr valptridx<segment>::magic_constant<segnum_t{0}> segment_first{};
#endif
}
#ifdef dsx

View file

@ -927,3 +927,8 @@ static inline unsigned get_player_or_team_color(unsigned pnum)
? get_team_color(get_team(pnum))
: get_player_color(pnum);
}
#define PUT_INTEL_SEGNUM(D,S) ( DXX_BEGIN_COMPOUND_STATEMENT { \
const segnum_t PUT_INTEL_SEGNUM = S; \
PUT_INTEL_SHORT(D, static_cast<uint16_t>(PUT_INTEL_SEGNUM)); \
} DXX_END_COMPOUND_STATEMENT )

View file

@ -479,7 +479,7 @@ struct object_rw
ubyte movement_source; // how this object moves
ubyte render_type; // how this object renders
ubyte flags; // misc flags
short segnum; // segment number containing object
uint16_t segnum; // segment number containing object
short attached_obj; // number of attached fireball object
vms_vector pos; // absolute x,y,z coordinate of center of object
vms_matrix orient; // orientation of object in world

View file

@ -33,7 +33,6 @@ COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED.
#include "dxxsconf.h"
#include "dsx-ns.h"
#ifdef __cplusplus
#include <cassert>
#include <cstdint>
#include <stdexcept>
@ -43,7 +42,6 @@ COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED.
#include "objnum.h"
#include "pack.h"
#ifdef dsx
namespace dsx {
// Returns true if segnum references a child, else returns false.
@ -122,6 +120,10 @@ enum class station_number : uint8_t
None = 0xff,
};
enum segnum_t : uint16_t
{
};
struct shared_side
{
struct illegal_type;
@ -338,7 +340,7 @@ struct group
};
#ifdef dsx
#define Highest_segment_index (Segments.get_count() - 1)
#define Highest_segment_index static_cast<segnum_t>(Segments.get_count() - 1)
DXX_VALPTRIDX_DEFINE_GLOBAL_FACTORIES(segment, seg, Segments);
#endif
@ -642,4 +644,3 @@ extern d_level_shared_segment_state LevelSharedSegmentState;
}
#endif
#endif

View file

@ -915,7 +915,6 @@ int rotate_segment_new(const vms_angvec &pbh)
{
vms_matrix tm1;
group::segment_array_type_t selected_segs_save;
int child_save;
int current_group_save;
if (!IS_CHILD(Cursegp->children[Side_opposite[Curside]]))
@ -936,7 +935,7 @@ int rotate_segment_new(const vms_angvec &pbh)
// Create list of segments to rotate.
// Sever connection between first seg to rotate and its connection on Side_opposite[Curside].
child_save = Cursegp->children[newseg_side]; // save connection we are about to sever
const auto child_save = Cursegp->children[newseg_side]; // save connection we are about to sever
Cursegp->children[newseg_side] = segment_none; // sever connection
create_group_list(Cursegp, GroupList[ROT_GROUP].segments, NULL); // create list of segments in group
Cursegp->children[newseg_side] = child_save; // restore severed connection

View file

@ -135,7 +135,7 @@ int SaveGameData()
if (Perm_player_segnum!=segment_none) {
if (save_segnum > Highest_segment_index)
save_segnum = 0;
save_segnum = {};
ConsoleObject->pos = save_pos;
const auto &&save_segp = vmsegptridx(save_segnum);

View file

@ -231,9 +231,7 @@ int wall_add_external_wall()
editor_status( "Cannot add external wall here - seg has children" );
return 0;
}
Cursegp->children[Curside] = -2;
Cursegp->children[Curside] = segment_exit;
return 1;
}

View file

@ -593,9 +593,9 @@ int save_mine_data_compiled(PHYSFS_File *SaveFile)
PHYSFSX_writeVector(SaveFile, i);
const auto Num_segments = LevelSharedSegmentState.Num_segments;
for (segnum_t segnum = 0; segnum < Num_segments; segnum++)
auto &&segment_range = partial_const_range(Segments, Num_segments);
for (const cscusegment seg : segment_range)
{
const cscusegment &&seg = vcsegptr(segnum);
{
sidemask_t bit_mask{};
for (const auto &&[sidenum, child] : enumerate(seg.s.children))
@ -689,8 +689,8 @@ int save_mine_data_compiled(PHYSFS_File *SaveFile)
#if defined(DXX_BUILD_DESCENT_II)
if (Gamesave_current_version > 5)
for (segnum_t i = 0; i < Num_segments; i++)
segment2_write(vcsegptr(i), SaveFile);
for (auto &s : segment_range)
segment2_write(s, SaveFile);
#endif
return 0;

View file

@ -172,8 +172,9 @@ namespace dsx {
// Scans the Segments array.
segnum_t get_free_segment_number(segment_array &Segments)
{
for (segnum_t segnum=0; segnum<MAX_SEGMENTS; segnum++)
if (Segments[segnum].segnum == segment_none) {
for (const auto &&[segnum, seg] : enumerate(Segments))
if (seg.segnum == segment_none)
{
++ LevelSharedSegmentState.Num_segments;
if (segnum > Highest_segment_index)
Segments.set_count(segnum + 1);
@ -181,8 +182,7 @@ segnum_t get_free_segment_number(segment_array &Segments)
}
Assert(0);
return 0;
return segnum_t{};
}
// -------------------------------------------------------------------------------
@ -936,8 +936,9 @@ int med_delete_segment(const vmsegptridx_t sp)
// If we deleted something which was not connected to anything, must now select a new current segment.
if (Cursegp == sp)
for (segnum_t s=0; s<MAX_SEGMENTS; s++)
if ((Segments[s].segnum != segment_none) && (s!=segnum) ) {
for (auto &&[s, seg] : enumerate(Segments))
if (seg.segnum != segment_none && s != segnum)
{
Cursegp = imsegptridx(s);
med_create_new_segment_from_cursegp();
break;
@ -1283,7 +1284,7 @@ void med_create_segment(const vmsegptridx_t sp,fix cx, fix cy, fix cz, fix lengt
auto &Vertices = LevelSharedVertexState.get_vertices();
++ LevelSharedSegmentState.Num_segments;
sp->segnum = 1; // What to put here? I don't know.
sp->segnum = segnum_t{1}; // What to put here? I don't know.
// Form connections to children, of which it has none.
for (auto &&[child, side] : zip(sp->children, sp->shared_segment::sides))
@ -1349,7 +1350,7 @@ void med_create_new_segment(const vms_vector &scale)
width = scale.x;
height = scale.y;
sp->segnum = 1; // What to put here? I don't know.
sp->segnum = segnum_t{1}; // What to put here? I don't know.
// Create relative-to-center vertices, which are the points on the box defined by length, width, height
auto &verts = sp->verts;

View file

@ -4626,7 +4626,7 @@ static void state_ai_local_to_ai_local_rw(const ai_local *ail, ai_local_rw *ail_
ail_rw->mode = static_cast<uint8_t>(ail->mode);
ail_rw->previous_visibility = static_cast<int8_t>(ail->previous_visibility);
ail_rw->rapidfire_count = ail->rapidfire_count;
ail_rw->goal_segment = ail->goal_segment;
ail_rw->goal_segment = underlying_value(ail->goal_segment);
#if defined(DXX_BUILD_DESCENT_I)
ail_rw->last_see_time = 0;
ail_rw->last_attack_time = 0;
@ -4832,7 +4832,10 @@ static void ai_local_read_swap(ai_local *ail, int swap, PHYSFS_File *fp)
ail->mode = static_cast<ai_mode>(PHYSFSX_readByte(fp));
ail->previous_visibility = static_cast<player_visibility_state>(PHYSFSX_readByte(fp));
ail->rapidfire_count = PHYSFSX_readByte(fp);
ail->goal_segment = PHYSFSX_readSXE16(fp, swap);
{
const auto s = segnum_t{static_cast<uint16_t>(PHYSFSX_readSXE16(fp, swap))};
ail->goal_segment = imsegidx_t::check_nothrow_index(s) ? s : segment_none;
}
PHYSFSX_readSXE32(fp, swap);
PHYSFSX_readSXE32(fp, swap);
ail->next_action_time = PHYSFSX_readSXE32(fp, swap);
@ -4844,7 +4847,10 @@ static void ai_local_read_swap(ai_local *ail, int swap, PHYSFS_File *fp)
ail->mode = static_cast<ai_mode>(PHYSFSX_readSXE32(fp, swap));
ail->previous_visibility = static_cast<player_visibility_state>(PHYSFSX_readSXE32(fp, swap));
ail->rapidfire_count = PHYSFSX_readSXE32(fp, swap);
ail->goal_segment = PHYSFSX_readSXE32(fp, swap);
{
const auto s = segnum_t{static_cast<uint16_t>(PHYSFSX_readSXE32(fp, swap))};
ail->goal_segment = imsegidx_t::check_nothrow_index(s) ? s : segment_none;
}
ail->next_action_time = PHYSFSX_readSXE32(fp, swap);
ail->next_fire = PHYSFSX_readSXE32(fp, swap);
ail->next_fire2 = PHYSFSX_readSXE32(fp, swap);
@ -4897,7 +4903,10 @@ static void ai_cloak_info_read_n_swap(ai_cloak_info *ci, int n, int swap, PHYSFS
tmptime32 = PHYSFSX_readSXE32(fp, swap);
ci->last_time = static_cast<fix64>(tmptime32);
#if defined(DXX_BUILD_DESCENT_II)
ci->last_segment = PHYSFSX_readSXE32(fp, swap);
{
const auto s = segnum_t{static_cast<uint16_t>(PHYSFSX_readSXE32(fp, swap))};
ci->last_segment = imsegidx_t::check_nothrow_index(s) ? s : segment_none;
}
#endif
PHYSFSX_readVectorX(fp, ci->last_position, swap);
}
@ -5022,16 +5031,24 @@ int ai_restore_state(PHYSFS_File *fp, int version, int swap)
ai_reset_all_paths();
if (version >= 21) {
unsigned Num_boss_teleport_segs = PHYSFSX_readSXE32(fp, swap);
unsigned Num_boss_gate_segs = PHYSFSX_readSXE32(fp, swap);
const xrange Num_boss_teleport_segs = static_cast<unsigned>(PHYSFSX_readSXE32(fp, swap));
const xrange Num_boss_gate_segs = static_cast<unsigned>(PHYSFSX_readSXE32(fp, swap));
Boss_gate_segs.clear();
for (unsigned i = 0; i < Num_boss_gate_segs; i++)
Boss_gate_segs.emplace_back(PHYSFSX_readSXE16(fp, swap));
for (const auto i : Num_boss_gate_segs)
{
(void)i;
const auto s = segnum_t{static_cast<uint16_t>(PHYSFSX_readSXE16(fp, swap))};
Boss_gate_segs.emplace_back(s);
}
Boss_teleport_segs.clear();
for (unsigned i = 0; i < Num_boss_teleport_segs; i++)
Boss_teleport_segs.emplace_back(PHYSFSX_readSXE16(fp, swap));
for (const auto i : Num_boss_teleport_segs)
{
(void)i;
const auto s = segnum_t{static_cast<uint16_t>(PHYSFSX_readSXE16(fp, swap))};
Boss_teleport_segs.emplace_back(s);
}
}
#endif

View file

@ -1546,7 +1546,7 @@ static void test_create_all_paths(fvmobjptridx &vmobjptridx, fvcsegptridx &vcseg
const shared_segment &sseg0 = segp0;
if (sseg0.segnum != segment_none)
{
range_for (const auto &&segp1, partial_range(vcsegptridx, static_cast<segnum_t>(segp0), vcsegptridx.count()))
for (const auto &&segp1 : partial_range(vcsegptridx, segp0.get_unchecked_index(), vcsegptridx.count()))
{
const shared_segment &sseg1 = segp1;
if (sseg1.segnum != segment_none)

View file

@ -820,8 +820,8 @@ static vmsegptridx_t choose_drop_segment(fvmsegptridx &vmsegptridx, fvcvertptr &
* Give up and pick a completely random segment. This is compatible
* with retail.
*/
std::uniform_int_distribution uid(0u, Highest_segment_index);
return vmsegptridx(vmsegidx_t(uid(mrd)));
std::uniform_int_distribution<typename std::underlying_type<segnum_t>::type> uid(0u, Highest_segment_index);
return vmsegptridx(vmsegidx_t(segnum_t{uid(mrd)}));
}
// ------------------------------------------------------------------------------------------------------
@ -1692,7 +1692,10 @@ void expl_wall_read_n_swap(fvmwallptr &vmwallptr, PHYSFS_File *const fp, const i
d.sidenum = SWAPINT(d.sidenum);
d.time = SWAPINT(d.time);
}
const icsegidx_t dseg = d.segnum;
const auto s = segnum_t{static_cast<uint16_t>(d.segnum)};
if (!vmsegidx_t::check_nothrow_index(s))
continue;
const icsegidx_t dseg = s;
if (dseg == segment_none)
continue;
range_for (auto &&wp, vmwallptr)
@ -1756,8 +1759,9 @@ vmsegidx_t choose_thief_recreation_segment(fvcsegptr &vcsegptr, fvcwallptr &vcwa
* Give up and pick a completely random segment. This is compatible
* with retail Descent 2.
*/
std::uniform_int_distribution uid(0u, Highest_segment_index);
return uid(mrd);
using distribution_type = typename std::underlying_type<segnum_t>::type;
std::uniform_int_distribution uid(distribution_type{0}, static_cast<distribution_type>(Highest_segment_index));
return segnum_t{uid(mrd)};
}
#endif
}

View file

@ -645,7 +645,8 @@ fvi_hit_type find_vector_intersection(const fvi_query &fq, fvi_info &hit_data)
{
Assert(fq.startseg <= Highest_segment_index);
hit_data.hit_pnt = *fq.p0;
hit_data.hit_seg = hit_data.hit_object = 0;
hit_data.hit_seg = segnum_t{};
hit_data.hit_object = 0;
hit_data.hit_side = side_none;
hit_data.hit_side_seg = segment_none;
return fvi_hit_type::BadP0;

View file

@ -2457,7 +2457,10 @@ namespace dsx {
*/
void flickering_light_read(flickering_light &fl, PHYSFS_File *fp)
{
fl.segnum = PHYSFSX_readShort(fp);
{
const auto s = segnum_t{static_cast<uint16_t>(PHYSFSX_readShort(fp))};
fl.segnum = vmsegidx_t::check_nothrow_index(s) ? s : segment_none;
}
const auto sidenum = build_sidenum_from_untrusted(PHYSFSX_readShort(fp));
fl.mask = PHYSFSX_readInt(fp);
fl.timer = PHYSFSX_readFix(fp);

View file

@ -408,7 +408,8 @@ static void read_children(shared_segment &segp, const sidemask_t bit_mask, PHYSF
{
if (bit_mask & build_sidemask(bit))
{
segp.children[bit] = PHYSFSX_readShort(LoadFile);
const auto s = segnum_t{static_cast<uint16_t>(PHYSFSX_readShort(LoadFile))};
segp.children[bit] = (imsegidx_t::check_nothrow_index(s) || s == segment_exit) ? s : segment_none;
} else
segp.children[bit] = segment_none;
}
@ -501,11 +502,21 @@ int load_mine_data_compiled(PHYSFS_File *LoadFile, const char *const Gamesave_cu
PHYSFSX_readVector(LoadFile, i);
const auto Num_segments = LevelSharedSegmentState.Num_segments;
for (segnum_t segnum=0; segnum < Num_segments; segnum++ ) {
const msmusegment segp = vmsegptr(segnum);
/* Editor builds need both the segment index and segment pointer.
* Non-editor builds need only the segment pointer.
*/
#if DXX_USE_EDITOR
#define dxx_segment_iteration_factory vmptridx
#else
#define dxx_segment_iteration_factory vmptr
#endif
for (auto &&segpi : partial_range(Segments.dxx_segment_iteration_factory, Num_segments))
#undef dxx_segment_iteration_factory
{
const msmusegment segp = segpi;
#if DXX_USE_EDITOR
segp.s.segnum = segnum;
segp.s.segnum = segpi;
segp.s.group = 0;
#endif

View file

@ -426,7 +426,10 @@ static void read_object(const vmobjptr_t obj,PHYSFS_File *f,int version)
}
obj->flags = PHYSFSX_readByte(f);
obj->segnum = PHYSFSX_readShort(f);
{
const auto s = segnum_t{static_cast<uint16_t>(PHYSFSX_readShort(f))};
obj->segnum = vmsegidx_t::check_nothrow_index(s) ? s : segment_none;
}
obj->attached_obj = object_none;
PHYSFSX_readVector(f, obj->pos);
@ -496,7 +499,10 @@ static void read_object(const vmobjptr_t obj,PHYSFS_File *f,int version)
obj->ctype.ai_info.SKIP_AI_COUNT = ai_info_flags[7];
obj->ctype.ai_info.REMOTE_OWNER = ai_info_flags[8];
obj->ctype.ai_info.REMOTE_SLOT_NUM = ai_info_flags[9];
obj->ctype.ai_info.hide_segment = PHYSFSX_readShort(f);
{
const auto s = segnum_t{static_cast<uint16_t>(PHYSFSX_readShort(f))};
obj->ctype.ai_info.hide_segment = imsegidx_t::check_nothrow_index(s) ? s : segment_none;
}
obj->ctype.ai_info.hide_index = PHYSFSX_readShort(f);
obj->ctype.ai_info.path_length = PHYSFSX_readShort(f);
obj->ctype.ai_info.cur_path_index = PHYSFSX_readShort(f);
@ -902,7 +908,7 @@ static void validate_segment_wall(const vcsegptridx_t seg, shared_side &side, co
if (connected_seg == segment_none)
{
rwn0 = wall_none;
LevelError("segment %u side %u wall %u has no child segment; removing orphan wall.", seg.get_unchecked_index(), underlying_value(sidenum), static_cast<unsigned>(wn0));
LevelError("segment %hu side %u wall %hu has no child segment; removing orphan wall.", seg.get_unchecked_index(), underlying_value(sidenum), underlying_value(wn0));
return;
}
const shared_segment &vcseg = *vcsegptr(connected_seg);
@ -910,14 +916,14 @@ static void validate_segment_wall(const vcsegptridx_t seg, shared_side &side, co
if (connected_side == side_none)
{
rwn0 = wall_none;
LevelError("segment %u side %u wall %u has child segment %u side %u, but child segment does not link back; removing orphan wall.", seg.get_unchecked_index(), underlying_value(sidenum), underlying_value(wn0), connected_seg, underlying_value(connected_side));
LevelError("segment %hu side %u wall %u has child segment %hu side %u, but child segment does not link back; removing orphan wall.", seg.get_unchecked_index(), underlying_value(sidenum), underlying_value(wn0), connected_seg, underlying_value(connected_side));
return;
}
const auto wn1 = vcseg.sides[connected_side].wall_num;
if (wn1 == wall_none)
{
rwn0 = wall_none;
LevelError("segment %u side %u wall %u has child segment %u side %u, but no wall; removing orphan wall.", seg.get_unchecked_index(), underlying_value(sidenum), static_cast<unsigned>(wn0), connected_seg, underlying_value(connected_side));
LevelError("segment %hu side %u wall %u has child segment %hu side %u, but no wall; removing orphan wall.", seg.get_unchecked_index(), underlying_value(sidenum), static_cast<unsigned>(wn0), connected_seg, underlying_value(connected_side));
return;
}
}
@ -1136,7 +1142,7 @@ static int load_game_data(
matcen_info_read(LoadFile, r);
#endif
// Set links in RobotCenters to Station array
range_for (const shared_segment &seg, partial_const_range(Segments, Highest_segment_index + 1))
for (const shared_segment &seg : partial_const_range(Segments, Segments.get_count()))
if (seg.special == segment_special::robotmaker)
if (seg.matcen_num == i)
r.fuelcen_num = seg.station_idx;
@ -1187,7 +1193,7 @@ static int load_game_data(
auto objsegnum = i.segnum;
if (objsegnum > Highest_segment_index) //bogus object
{
Warning("Object %p is in non-existent segment %i, highest=%i", &i, objsegnum, Highest_segment_index);
Warning("Object %p is in non-existent segment %hu, highest=%hu", &i, objsegnum, Highest_segment_index);
i.type = OBJ_NONE;
}
else {
@ -1437,7 +1443,10 @@ int load_level(
Secret_return_orient.uvec.y = 0;
Secret_return_orient.uvec.z = F1_0;
} else {
LevelSharedSegmentState.Secret_return_segment = PHYSFSX_readInt(LoadFile);
{
const auto s = segnum_t{static_cast<uint16_t>(PHYSFSX_readInt(LoadFile))};
LevelSharedSegmentState.Secret_return_segment = vmsegidx_t::check_nothrow_index(s) ? s : segment_none;
}
Secret_return_orient.rvec.x = PHYSFSX_readInt(LoadFile);
Secret_return_orient.rvec.y = PHYSFSX_readInt(LoadFile);
Secret_return_orient.rvec.z = PHYSFSX_readInt(LoadFile);
@ -1470,7 +1479,7 @@ int load_level(
*/
if (Current_mission && !d_stricmp("Descent 2: Counterstrike!", Current_mission->mission_name) && !d_stricmp("d2levc-4.rl2", filename))
{
shared_segment &s104 = *vmsegptr(vmsegidx_t(104));
shared_segment &s104 = *vmsegptr(segnum_t{104});
auto &s104v0 = *vmvertptr(s104.verts[segment_relative_vertnum::_0]);
auto &s104s1 = s104.sides[sidenum_t::WTOP];
auto &s104s1n0 = s104s1.normals[0];

View file

@ -531,8 +531,9 @@ int check_segment_connections(void)
{
shared_segment &rseg = *seg;
const shared_segment &rcseg = *cseg;
const unsigned segi = seg.get_unchecked_index();
LevelError("Segment #%u side %u has asymmetric link to segment %u. Coercing to segment_none; Segments[%u].children={%hu, %hu, %hu, %hu, %hu, %hu}, Segments[%u].children={%hu, %hu, %hu, %hu, %hu, %hu}.", segi, underlying_value(sidenum), csegnum, segi, rseg.children[sidenum_t::WLEFT], rseg.children[sidenum_t::WTOP], rseg.children[sidenum_t::WRIGHT], rseg.children[sidenum_t::WBOTTOM], rseg.children[sidenum_t::WBACK], rseg.children[sidenum_t::WFRONT], csegnum, rcseg.children[sidenum_t::WLEFT], rcseg.children[sidenum_t::WTOP], rcseg.children[sidenum_t::WRIGHT], rcseg.children[sidenum_t::WBOTTOM], rcseg.children[sidenum_t::WBACK], rcseg.children[sidenum_t::WFRONT]);
const auto segi = underlying_value(seg.get_unchecked_index());
const auto csegi = underlying_value(csegnum);
LevelError("Segment #%hu side %u has asymmetric link to segment %hu. Coercing to segment_none; Segments[%hu].children={%hu, %hu, %hu, %hu, %hu, %hu}, Segments[%u].children={%hu, %hu, %hu, %hu, %hu, %hu}.", segi, underlying_value(sidenum), csegi, segi, rseg.children[sidenum_t::WLEFT], rseg.children[sidenum_t::WTOP], rseg.children[sidenum_t::WRIGHT], rseg.children[sidenum_t::WBOTTOM], rseg.children[sidenum_t::WBACK], rseg.children[sidenum_t::WFRONT], csegi, rcseg.children[sidenum_t::WLEFT], rcseg.children[sidenum_t::WTOP], rcseg.children[sidenum_t::WRIGHT], rcseg.children[sidenum_t::WBOTTOM], rcseg.children[sidenum_t::WBACK], rcseg.children[sidenum_t::WFRONT]);
rseg.children[sidenum] = segment_none;
errors = 1;
continue;
@ -773,7 +774,7 @@ icsegptridx_t find_point_seg(const d_level_shared_segment_state &LevelSharedSegm
namespace dsx {
#if defined(DXX_BUILD_DESCENT_I)
static inline void add_to_fcd_cache(int seg0, int seg1, int depth, vm_distance dist)
static inline void add_to_fcd_cache(segnum_t seg0, segnum_t seg1, int depth, vm_distance dist)
{
(void)(seg0||seg1||depth||dist);
}
@ -806,7 +807,7 @@ void flush_fcd_cache(void)
namespace {
// ----------------------------------------------------------------------------------------------------------
static void add_to_fcd_cache(int seg0, int seg1, int depth, vm_distance dist)
static void add_to_fcd_cache(segnum_t seg0, segnum_t seg1, int depth, vm_distance dist)
{
if (dist > MIN_CACHE_FCD_DIST) {
Fcd_cache[Fcd_index].seg0 = seg0;
@ -1050,7 +1051,7 @@ void create_shortpos_little(const d_level_shared_segment_state &LevelSharedSegme
spp.xo = INTEL_SHORT(spp.xo);
spp.yo = INTEL_SHORT(spp.yo);
spp.zo = INTEL_SHORT(spp.zo);
spp.segment = INTEL_SHORT(spp.segment);
spp.segment = segnum_t{INTEL_SHORT(underlying_value(spp.segment))};
spp.velx = INTEL_SHORT(spp.velx);
spp.vely = INTEL_SHORT(spp.vely);
spp.velz = INTEL_SHORT(spp.velz);
@ -1075,7 +1076,7 @@ void extract_shortpos_little(const vmobjptridx_t objp, const shortpos *spp)
objp->orient.uvec.z = *sp++ << MATRIX_PRECISION;
objp->orient.fvec.z = *sp++ << MATRIX_PRECISION;
const segnum_t segnum = INTEL_SHORT(spp->segment);
const auto segnum = segnum_t{INTEL_SHORT(underlying_value(spp->segment))};
Assert(segnum <= Highest_segment_index);
@ -1586,7 +1587,7 @@ void validate_segment_all(d_level_shared_segment_state &LevelSharedSegmentState)
}
#if DXX_USE_EDITOR
range_for (shared_segment &s, partial_range(Segments, Highest_segment_index + 1, Segments.size()))
for (shared_segment &s : partial_range(Segments, Segments.get_count(), Segments.size()))
s.segnum = segment_none;
#endif
}

View file

@ -967,10 +967,10 @@ static ushort netmisc_calc_checksum()
do_checksum_calc(reinterpret_cast<uint8_t *>(&t), 4, &sum1, &sum2);
}
}
range_for (auto &j, i.s.children)
for (const typename std::underlying_type<segnum_t>::type j : i.s.children)
{
s = INTEL_SHORT(j);
do_checksum_calc(reinterpret_cast<uint8_t *>(&s), 2, &sum1, &sum2);
const auto s = INTEL_SHORT(j);
do_checksum_calc(reinterpret_cast<const uint8_t *>(&s), 2, &sum1, &sum2);
}
range_for (const auto vn, i.s.verts)
{

View file

@ -1659,7 +1659,13 @@ static void multi_do_position(fvmobjptridx &vmobjptridx, const playernum_t pnum,
qpp.pos.x = GET_INTEL_INT(&buf[count]); count += 4;
qpp.pos.y = GET_INTEL_INT(&buf[count]); count += 4;
qpp.pos.z = GET_INTEL_INT(&buf[count]); count += 4;
qpp.segment = GET_INTEL_SHORT(&buf[count]); count += 2;
if (const auto s = segnum_t{GET_INTEL_SHORT(&buf[count])}; vmsegidx_t::check_nothrow_index(s))
{
qpp.segment = s;
count += 2;
}
else
return;
qpp.vel.x = GET_INTEL_INT(&buf[count]); count += 4;
qpp.vel.y = GET_INTEL_INT(&buf[count]); count += 4;
qpp.vel.z = GET_INTEL_INT(&buf[count]); count += 4;
@ -2091,7 +2097,6 @@ namespace {
static void multi_do_door_open(fvmwallptr &vmwallptr, const uint8_t *const buf)
{
const segnum_t segnum = GET_INTEL_SHORT(&buf[1]);
const auto uside = build_sidenum_from_untrusted(buf[3]);
if (!uside)
return;
@ -2100,7 +2105,7 @@ static void multi_do_door_open(fvmwallptr &vmwallptr, const uint8_t *const buf)
ubyte flag= buf[4];
#endif
const auto &&useg = vmsegptridx.check_untrusted(segnum);
const auto &&useg = vmsegptridx.check_untrusted(segnum_t{GET_INTEL_SHORT(&buf[1])});
if (!useg)
return;
const auto &&seg = *useg;
@ -2173,7 +2178,11 @@ static void multi_do_create_powerup(fvmsegptridx &vmsegptridx, const playernum_t
count++;
powerup_type = buf[count++];
const auto &&useg = vmsegptridx.check_untrusted(GET_INTEL_SHORT(&buf[count]));
/* Casting the untrusted network input to segnum_t is safe here, since it
* is immediately passed to `check_untrusted`, which validates that the
* index is reasonable.
*/
const auto &&useg = vmsegptridx.check_untrusted(segnum_t{GET_INTEL_SHORT(&buf[count])});
if (!useg)
return;
const auto &&segnum = *useg;
@ -2278,7 +2287,7 @@ static void multi_do_effect_blowup(const playernum_t pnum, const ubyte *buf)
multi::dispatch->do_protocol_frame(1, 0); // force packets to be sent, ensuring this packet will be attached to following MULTI_TRIGGER
const auto &&useg = vmsegptridx.check_untrusted(GET_INTEL_SHORT(&buf[2]));
const auto &&useg = vmsegptridx.check_untrusted(segnum_t{GET_INTEL_SHORT(&buf[2])});
if (!useg)
return;
const auto uside = build_sidenum_from_untrusted(buf[4]);
@ -2745,7 +2754,7 @@ void multi_send_position(object &obj)
PUT_INTEL_INT(&multibuf[count], qpp.pos.x); count += 4;
PUT_INTEL_INT(&multibuf[count], qpp.pos.y); count += 4;
PUT_INTEL_INT(&multibuf[count], qpp.pos.z); count += 4;
PUT_INTEL_SHORT(&multibuf[count], qpp.segment); count += 2;
PUT_INTEL_SEGNUM(&multibuf[count], qpp.segment); count += 2;
PUT_INTEL_INT(&multibuf[count], qpp.vel.x); count += 4;
PUT_INTEL_INT(&multibuf[count], qpp.vel.y); count += 4;
PUT_INTEL_INT(&multibuf[count], qpp.vel.z); count += 4;
@ -2873,7 +2882,7 @@ void multi_send_door_open(const vcsegidx_t segnum, const sidenum_t side, const w
{
multi_command<MULTI_DOOR_OPEN> multibuf;
// When we open a door make sure everyone else opens that door
PUT_INTEL_SHORT(&multibuf[1], segnum );
PUT_INTEL_SEGNUM(&multibuf[1], segnum);
multibuf[3] = underlying_value(side);
#if defined(DXX_BUILD_DESCENT_I)
(void)flag;
@ -2892,7 +2901,7 @@ void multi_send_door_open_specific(const playernum_t pnum, const vcsegidx_t segn
// Assert (pnum>-1 && pnum<N_players);
multi_command<MULTI_DOOR_OPEN> multibuf;
PUT_INTEL_SHORT(&multibuf[1], segnum);
PUT_INTEL_SEGNUM(&multibuf[1], segnum);
multibuf[3] = static_cast<int8_t>(side);
multibuf[4] = underlying_value(flag);
@ -2966,7 +2975,7 @@ void multi_send_create_powerup(const powerup_type_t powerup_type, const vcsegidx
multi_command<MULTI_CREATE_POWERUP> multibuf;
multibuf[count] = Player_num; count += 1;
multibuf[count] = powerup_type; count += 1;
PUT_INTEL_SHORT(&multibuf[count], segnum ); count += 2;
PUT_INTEL_SEGNUM(&multibuf[count], segnum); count += 2;
PUT_INTEL_SHORT(&multibuf[count], objnum ); count += 2;
if constexpr (words_bigendian)
{
@ -3094,7 +3103,7 @@ void multi_send_effect_blowup(const vcsegidx_t segnum, const sidenum_t side, con
count += 1;
multi_command<MULTI_EFFECT_BLOWUP> multibuf;
multibuf[count] = Player_num; count += 1;
PUT_INTEL_SHORT(&multibuf[count], segnum); count += 2;
PUT_INTEL_SEGNUM(&multibuf[count], segnum); count += 2;
multibuf[count] = static_cast<int8_t>(side); count += 1;
PUT_INTEL_INT(&multibuf[count], pnt.x); count += 4;
PUT_INTEL_INT(&multibuf[count], pnt.y); count += 4;
@ -4132,7 +4141,7 @@ void multi_send_light_specific (const playernum_t pnum, const vcsegptridx_t segn
// Assert (pnum>-1 && pnum<N_players);
multi_command<MULTI_LIGHT> multibuf;
PUT_INTEL_SHORT(&multibuf[count], segnum);
PUT_INTEL_SEGNUM(&multibuf[count], segnum);
count += sizeof(uint16_t);
multibuf[count] = underlying_value(val); count++;
@ -4150,8 +4159,7 @@ static void multi_do_light (const ubyte *buf)
{
const auto sides = buf[3];
const segnum_t seg = GET_INTEL_SHORT(&buf[1]);
const auto &&usegp = vmsegptridx.check_untrusted(seg);
const auto &&usegp = vmsegptridx.check_untrusted(segnum_t{GET_INTEL_SHORT(&buf[1])});
if (!usegp)
return;
const auto &&segp = *usegp;
@ -6110,7 +6118,10 @@ void multi_object_rw_to_object(const object_rw *const obj_rw, object &obj)
obj.render_type = RT_NONE;
}
obj.flags = obj_rw->flags;
obj.segnum = obj_rw->segnum;
{
const auto s = segnum_t{obj_rw->segnum};
obj.segnum = vmsegidx_t::check_nothrow_index(s) ? s : segment_none;
}
/* obj->attached_obj cleared by caller */
obj.pos = obj_rw->pos;
obj.orient = obj_rw->orient;
@ -6196,7 +6207,10 @@ void multi_object_rw_to_object(const object_rw *const obj_rw, object &obj)
obj.ctype.ai_info.SKIP_AI_COUNT = obj_rw->ctype.ai_info.flags[7];
obj.ctype.ai_info.REMOTE_OWNER = obj_rw->ctype.ai_info.flags[8];
obj.ctype.ai_info.REMOTE_SLOT_NUM = obj_rw->ctype.ai_info.flags[9];
obj.ctype.ai_info.hide_segment = obj_rw->ctype.ai_info.hide_segment;
{
const auto s = segnum_t{obj_rw->ctype.ai_info.hide_segment};
obj.ctype.ai_info.hide_segment = vmsegidx_t::check_nothrow_index(s) ? s : segment_none;
}
obj.ctype.ai_info.hide_index = obj_rw->ctype.ai_info.hide_index;
obj.ctype.ai_info.path_length = obj_rw->ctype.ai_info.path_length;
obj.ctype.ai_info.cur_path_index = obj_rw->ctype.ai_info.cur_path_index;

View file

@ -478,7 +478,7 @@ void multi_send_robot_position_sub(const vmobjptridx_t objnum, int now)
PUT_INTEL_INT(&multibuf[loc], qpp.pos.x); loc += 4;
PUT_INTEL_INT(&multibuf[loc], qpp.pos.y); loc += 4;
PUT_INTEL_INT(&multibuf[loc], qpp.pos.z); loc += 4;
PUT_INTEL_SHORT(&multibuf[loc], qpp.segment); loc += 2;
PUT_INTEL_SEGNUM(&multibuf[loc], qpp.segment); loc += 2;
PUT_INTEL_INT(&multibuf[loc], qpp.vel.x); loc += 4;
PUT_INTEL_INT(&multibuf[loc], qpp.vel.y); loc += 4;
PUT_INTEL_INT(&multibuf[loc], qpp.vel.z); loc += 4;
@ -707,7 +707,7 @@ static void multi_send_create_robot_powerups(const object_base &del_obj)
multibuf[loc] = del_obj.contains_count; loc += 1;
multibuf[loc] = del_obj.contains_type; loc += 1;
multibuf[loc] = del_obj.contains_id; loc += 1;
PUT_INTEL_SHORT(&multibuf[loc], del_obj.segnum); loc += 2;
PUT_INTEL_SEGNUM(&multibuf[loc], del_obj.segnum); loc += 2;
if constexpr (words_bigendian)
{
vms_vector swapped_vec;
@ -836,7 +836,7 @@ void multi_do_robot_position(const playernum_t pnum, const ubyte *buf)
if ((robot->type != OBJ_ROBOT) || (robot->flags & OF_EXPLODING)) {
return;
}
if (robot->ctype.ai_info.REMOTE_OWNER != pnum)
{
if (robot->ctype.ai_info.REMOTE_OWNER == -1)
@ -866,7 +866,13 @@ void multi_do_robot_position(const playernum_t pnum, const ubyte *buf)
qpp.pos.x = GET_INTEL_INT(&buf[loc]); loc += 4;
qpp.pos.y = GET_INTEL_INT(&buf[loc]); loc += 4;
qpp.pos.z = GET_INTEL_INT(&buf[loc]); loc += 4;
qpp.segment = GET_INTEL_SHORT(&buf[loc]); loc += 2;
if (const auto s = segnum_t{GET_INTEL_SHORT(&buf[loc])}; vmsegidx_t::check_nothrow_index(s))
{
qpp.segment = s;
loc += 2;
}
else
return;
qpp.vel.x = GET_INTEL_INT(&buf[loc]); loc += 4;
qpp.vel.y = GET_INTEL_INT(&buf[loc]); loc += 4;
qpp.vel.z = GET_INTEL_INT(&buf[loc]); loc += 4;
@ -1250,7 +1256,9 @@ void multi_do_create_robot_powerups(const playernum_t pnum, const ubyte *buf)
uint8_t contains_count = buf[loc]; loc += 1;
uint8_t contains_type = buf[loc]; loc += 1;
uint8_t contains_id = buf[loc]; loc += 1;
segnum_t segnum = GET_INTEL_SHORT(buf + loc); loc += 2;
const auto segnum = segnum_t{GET_INTEL_SHORT(&buf[loc])}; loc += 2;
if (!vmsegidx_t::check_nothrow_index(segnum))
return;
vms_vector pos;
memcpy(&pos, &buf[loc], sizeof(pos)); loc += 12;

View file

@ -5661,7 +5661,7 @@ void net_udp_send_pdata()
PUT_INTEL_INT(&buf[len], qpp.pos.x); len += 4;
PUT_INTEL_INT(&buf[len], qpp.pos.y); len += 4;
PUT_INTEL_INT(&buf[len], qpp.pos.z); len += 4;
PUT_INTEL_SHORT(&buf[len], qpp.segment); len += 2;
PUT_INTEL_SEGNUM(&buf[len], qpp.segment); len += 2;
PUT_INTEL_INT(&buf[len], qpp.vel.x); len += 4;
PUT_INTEL_INT(&buf[len], qpp.vel.y); len += 4;
PUT_INTEL_INT(&buf[len], qpp.vel.z); len += 4;
@ -5710,7 +5710,13 @@ void net_udp_process_pdata(const uint8_t *data, uint_fast32_t data_len, const _s
pd.qpp.pos.x = GET_INTEL_INT(&data[len]); len += 4;
pd.qpp.pos.y = GET_INTEL_INT(&data[len]); len += 4;
pd.qpp.pos.z = GET_INTEL_INT(&data[len]); len += 4;
pd.qpp.segment = GET_INTEL_SHORT(&data[len]); len += 2;
if (const auto s = segnum_t{GET_INTEL_SHORT(&data[len])}; vmsegidx_t::check_nothrow_index(s))
{
len += 2;
pd.qpp.segment = s;
}
else
return;
pd.qpp.vel.x = GET_INTEL_INT(&data[len]); len += 4;
pd.qpp.vel.y = GET_INTEL_INT(&data[len]); len += 4;
pd.qpp.vel.z = GET_INTEL_INT(&data[len]); len += 4;

View file

@ -446,9 +446,9 @@ static void nd_read_short(uint16_t *const s)
static void nd_read_segnum16(segnum_t &s)
{
short i;
uint16_t i;
nd_read_short(&i);
s = i;
s = segnum_t{i};
}
static void nd_read_objnum16(objnum_t &o)
@ -476,9 +476,9 @@ static void nd_read_int(unsigned *i)
static void nd_read_segnum32(segnum_t &s)
{
int i;
int32_t i;
nd_read_int(&i);
s = i;
s = segnum_t{static_cast<uint16_t>(i)};
}
static void nd_read_objnum32(objnum_t &o)
@ -550,7 +550,7 @@ static void nd_read_shortpos(object_base &obj)
nd_read_short(&sp.xo);
nd_read_short(&sp.yo);
nd_read_short(&sp.zo);
nd_read_short(&sp.segment);
nd_read_segnum16(sp.segment);
nd_read_short(&sp.velx);
nd_read_short(&sp.vely);
nd_read_short(&sp.velz);
@ -2162,7 +2162,7 @@ static int newdemo_read_frame_information(int rewrite)
// HACK HACK HACK -- the viewer to segment 0 for bogus view.
if (segnum > Highest_segment_index)
segnum = 0;
segnum = {};
obj_link_unchecked(Objects.vmptr, viewer_vmobj, Segments.vmptridx(segnum));
}
}
@ -2822,12 +2822,13 @@ static int newdemo_read_frame_information(int rewrite)
case ND_EVENT_WALL_SET_TMAP_NUM1: {
uint16_t seg, cseg, tmap;
segnum_t seg, cseg;
uint16_t tmap;
uint8_t side, cside;
nd_read_short(&seg);
nd_read_segnum16(seg);
nd_read_byte(&side);
nd_read_short(&cseg);
nd_read_segnum16(cseg);
nd_read_byte(&cside);
nd_read_short( &tmap );
if (rewrite)
@ -2845,12 +2846,13 @@ static int newdemo_read_frame_information(int rewrite)
}
case ND_EVENT_WALL_SET_TMAP_NUM2: {
uint16_t seg, cseg, tmap;
segnum_t seg, cseg;
uint16_t tmap;
uint8_t side, cside;
nd_read_short(&seg);
nd_read_segnum16(seg);
nd_read_byte(&side);
nd_read_short(&cseg);
nd_read_segnum16(cseg);
nd_read_byte(&cside);
nd_read_short( &tmap );
if (rewrite)

View file

@ -63,7 +63,10 @@ namespace dsx {
*/
void delta_light_read(delta_light *dl, PHYSFS_File *fp)
{
dl->segnum = PHYSFSX_readShort(fp);
{
const auto s = segnum_t{static_cast<uint16_t>(PHYSFSX_readShort(fp))};
dl->segnum = vmsegidx_t::check_nothrow_index(s) ? s : segment_none;
}
dl->sidenum = build_sidenum_from_untrusted(PHYSFSX_readByte(fp)).value_or(sidenum_t::WLEFT);
PHYSFSX_readByte(fp);
dl->vert_light[side_relative_vertnum::_0] = PHYSFSX_readByte(fp);
@ -78,7 +81,10 @@ void delta_light_read(delta_light *dl, PHYSFS_File *fp)
*/
void dl_index_read(dl_index *di, PHYSFS_File *fp)
{
di->segnum = PHYSFSX_readShort(fp);
{
const auto s = segnum_t{static_cast<uint16_t>(PHYSFSX_readShort(fp))};
di->segnum = vmsegidx_t::check_nothrow_index(s) ? s : segment_none;
}
di->sidenum = build_sidenum_from_untrusted(PHYSFSX_readByte(fp)).value_or(sidenum_t::WLEFT);
di->count = PHYSFSX_readByte(fp);
di->index = PHYSFSX_readShort(fp);

View file

@ -524,7 +524,10 @@ static void state_object_rw_to_object(const object_rw *const obj_rw, object &obj
obj.render_type = RT_NONE;
}
obj.flags = obj_rw->flags;
obj.segnum = obj_rw->segnum;
{
const auto s = segnum_t{obj_rw->segnum};
obj.segnum = vmsegidx_t::check_nothrow_index(s) ? s : segment_none;
}
obj.attached_obj = obj_rw->attached_obj;
obj.pos.x = obj_rw->pos.x;
obj.pos.y = obj_rw->pos.y;
@ -617,7 +620,10 @@ static void state_object_rw_to_object(const object_rw *const obj_rw, object &obj
obj.ctype.ai_info.SKIP_AI_COUNT = obj_rw->ctype.ai_info.flags[7];
obj.ctype.ai_info.REMOTE_OWNER = obj_rw->ctype.ai_info.flags[8];
obj.ctype.ai_info.REMOTE_SLOT_NUM = obj_rw->ctype.ai_info.flags[9];
obj.ctype.ai_info.hide_segment = obj_rw->ctype.ai_info.hide_segment;
{
const auto s = segnum_t{obj_rw->ctype.ai_info.hide_segment};
obj.ctype.ai_info.hide_segment = vmsegidx_t::check_nothrow_index(s) ? s : segment_none;
}
obj.ctype.ai_info.hide_index = obj_rw->ctype.ai_info.hide_index;
obj.ctype.ai_info.path_length = obj_rw->ctype.ai_info.path_length;
obj.ctype.ai_info.cur_path_index = obj_rw->ctype.ai_info.cur_path_index;

View file

@ -593,7 +593,10 @@ void v26_trigger_read(PHYSFS_File *fp, trigger &t)
t.value = PHYSFSX_readInt(fp);
PHYSFSX_readInt(fp);
for (unsigned i=0; i < MAX_WALLS_PER_LINK; i++ )
t.seg[i] = PHYSFSX_readShort(fp);
{
const auto s = segnum_t{static_cast<uint16_t>(PHYSFSX_readShort(fp))};
t.seg[i] = vmsegidx_t::check_nothrow_index(s) ? s : segment_none;
}
for (unsigned i=0; i < MAX_WALLS_PER_LINK; i++ )
{
auto s = build_sidenum_from_untrusted(PHYSFSX_readShort(fp));
@ -617,7 +620,10 @@ void v29_trigger_read(v29_trigger *t, PHYSFS_File *fp)
PHYSFSX_readByte(fp);
t->num_links = PHYSFSX_readShort(fp);
for (unsigned i=0; i<MAX_WALLS_PER_LINK; i++ )
t->seg[i] = PHYSFSX_readShort(fp);
{
const auto s = segnum_t{static_cast<uint16_t>(PHYSFSX_readShort(fp))};
t->seg[i] = vmsegidx_t::check_nothrow_index(s) ? s : segment_none;
}
for (unsigned i=0; i<MAX_WALLS_PER_LINK; i++ )
{
auto s = build_sidenum_from_untrusted(PHYSFSX_readShort(fp));
@ -637,7 +643,10 @@ extern void v30_trigger_read(v30_trigger *t, PHYSFS_File *fp)
t->value = PHYSFSX_readFix(fp);
PHYSFSX_readFix(fp);
for (unsigned i=0; i<MAX_WALLS_PER_LINK; i++ )
t->seg[i] = PHYSFSX_readShort(fp);
{
const auto s = segnum_t{static_cast<uint16_t>(PHYSFSX_readShort(fp))};
t->seg[i] = vmsegidx_t::check_nothrow_index(s) ? s : segment_none;
}
for (unsigned i=0; i<MAX_WALLS_PER_LINK; i++ )
t->side[i] = build_sidenum_from_untrusted(PHYSFSX_readShort(fp)).value_or(sidenum_t::WLEFT);
}