Many of these locals are wasteful, since they are always sized to the
biggest buffer required. This is the minimal and safe solution. Future
work will tune them to the correct size.
Remove the `basic_` prefix from valptridx<T>::basic_ptr, ::basic_idx,
and ::basic_ptridx. Since the public names are typedef aliases of these
classes, these class names appear frequently in debug information and
error messages. The `basic_` prefix is unnecessary. Remove it.
git grep -lz '\<basic_\(ptr\|ptridx\|idx\)\>' -- common/include/ | xargs -0 sed -i -e 's/\<basic_\(ptr\|ptridx\|idx\)\>/\1/g'
On Windows, the hook function blocks until the user dismisses the
message box. Print the message before opening the message box so that
it is available on the console, if one exists.
Early implementations of integer_sequence used a naive implementation
that required one level of template depth per additional integer in the
sequence. Rebirth uses a private alternate implementation named
make_tree_index_sequence that requires only log(N) steps for an
N-element index_sequence. Recent versions of gcc ship a log(N) version
of integer_sequence. Probe for that version and, if found, use it
instead of the private implementation, on the theory that the compiler
writers did at least as good a job as I did, and possibly better if they
were able to leverage compiler implementation details.
- Add wrappers for PHYSFS_read and its convenience functions. Poison
the memory before calling PHYSFS, so that any uninitialized bytes
(likely caused by a short read) are reported if the caller tries to
access the value anyway.
- Add SConstruct options to enable wrapping, so that users do not need
to enumerate the wrapped functions manually.
- Fix link failure when using LTO+wrappers.
d2x::segment has all members of d1x::segment, as well as two new members
exclusive to d2x::segment. Structure layout is such that d1x::segment
requires the same size allocation, and places anonymous pad members in
the locations that become named members in d2x::segment. Thus, reusing
d2x::segment for d1x::segment does not change the size of the structure
nor the offsets of any members used. This reuse may enable some
functions to be better shared by the dsx project.
Future work will introduce uses of d1x/d2x in the other game when the
types can be usefully shared. Extend the anti-nesting guards to cover
mistakes that might arise when referring to the namespaces by their
real name, rather than the alias name dsx.
`value` is generic and unclear. It is always meant to be used as an
index into the Station array, so rename it `station_idx` to show this.
Define and consistently use `station_none` to represent that no station
is assigned.
Using precompiled headers includes vers_id.h into
similar/main/newdemo.cpp. gcc-4.9 reports a conflict between vers_id.h
`extern const char g_descent_build_datetime[21]` and newdemo.cpp macro
generated `extern const char g_descent_build_datetime[]`. The size is
only needed in the definition, so remove it from the declaration to
align with the macro-generated extern.
Delete stub "compiler-type_traits.h" header. Redirect all uses to the
standard <type_traits> header.
git grep -wlz 'compiler-type_traits.h' -- '*.cpp' '*.h' | xargs -0 perl -p -i <<EOF
BEGIN {
$i = 0;
}
if (($i == 1 && $_ eq "\n") || ($i < 2 && /^#include "/)) {
# First blank line or first user-include after a system-include.
# Print, then never again for this file.
print "#include <type_traits>\n";
$i = 2;
} elsif ($i == 0) {
$i = 1 if (/^#include </);
} elsif ($_ eq "#include \"compiler-type_traits.h\"\n") {
# Remove this line if found.
$_ = '';
}
# Reset state machine when moving to next file.
$i = 0 if eof;
EOF
All supported compilers have an acceptable <type_traits>. Commit
4cb3d46148 ("Move <type_traits> test to Cxx11RequiredFeature") made
<type_traits> support mandatory in August and no one has objected.
Remove the indirection and use namespace std directly for type_traits
members.
Early unification efforts missed this one because it was in gamemine.c
for Descent 1, but segment.c for Descent 2. Move it to gamemine.cpp for
both, so that it can be static for both games.
Previously, valptridx used PREFIX for allow-invalid+mutable, c#PREFIX
for allow-invalid+const, v#PREFIX for require-valid+mutable, vc#PREFIX
for require-valid+const. Convert the types, factories, and all usage
sites to specify a qualifier for all four combinations:
im#PREFIX -> allow-invalid+mutable
ic#PREFIX -> allow-invalid+const
vm#PREFIX -> require-valid+mutable
vc#PREFIX -> require-valid+const
Changes to common/include/valptridx.h and common/include/fwd-valptridx.h
are manual. All other changes are generated by:
git grep -lz -e '\(obj\|seg\|clwall\|wall\|actdoor\|trg\)\(ptridx\|ptr\|idx\)\(_t\)\?\>' | xargs -0 sed -i -e 's/\<\(v\?\)\(\(obj\|seg\|clwall\|wall\|actdoor\|trg\)\(ptridx\|ptr\|idx\)\(_t\)\?\)\>/\1m\2/g'
for the 'm' prefix and:
git grep -lz -e '\(obj\|seg\|clwall\|wall\|actdoor\|trg\)\(ptridx\|ptr\|idx\)\(_t\)\?\>' | xargs -0 sed -i -e 's/\<\([cm]\(obj\|seg\|clwall\|wall\|actdoor\|trg\)\(ptridx\|ptr\|idx\)\(_t\)\?\)\>/i&/g'
for the 'i' prefix.
Past releases had a debug-only assertion that 25 was sufficient, but
then dynamically allocated enough storage for larger models as needed.
Commit 22a34809ee ("Move interpreter g3s_lrgb onto stack") added a
hard limit of 25, but did not detect attempts to exceed this. Custom
models that exceeded 25 would cause a stack buffer overwrite and likely
crash. Raise the limit to 64 and add sanity checking to refuse to
render models that exceed MAX_POINTS_PER_POLY.
Fixes: 22a34809ee ("Move interpreter g3s_lrgb onto stack")
For switch cases where existing comments or code flow logic obviously
intended to fall through, add a gcc-7 /*-fallthrough*/ comment to
silence warnings about this. Some cases which are less obvious are not
converted, so the code does not yet compile clean with
-Wimplicit-fallthrough.
Reported-by: parkerlreed <https://github.com/dxx-rebirth/dxx-rebirth/issues/338>
The dump logger probes for the end of the stack, then rounds down to the
nearest paragraph boundary to simplify the logic in the hexdump routine.
The termination condition in the hexdump code assumed that there would
exist an integer N such that (`start` + (16 * N) == `end`). Since `end`
is rounded to a multiple of 16, this held if and only if `start` is also
a multiple of 16. In practice, this tended to happen, but it was not
guaranteed by the code. If it ever failed to happen, then the hexdump
routine would not terminate and would instead perform an invalid read
beyond the edge of the stack.
Modify the hexdump routine to round `start` to a multiple of 16 so that
the termination condition works as intended. This has the useful side
effect that hex dumps now always start paragraph aligned. When the
stack was not paragraph aligned, this change will cause the hexdump to
show bytes below the stack pointer at the time of the fault. However,
the stack requirements of the handler itself ensure that these bytes
will be valid.
Hat labels reserve an extra character for the arrow, which partially
masked this error. When used buttons requires more characters than (1
+ used hats), the buffer had insufficient space and the label was
truncated.
x86_64-w64-mingw32-g++ -Wformat handling misparses the std::size_t
format string, causing a spurious error.
common/main/valptridx.tcc: In function 'void untyped_index_mismatch_exception::prepare_report(const char*, unsigned int, const void*, long int, const void*, const void*, char (&)[229], std::size_t)':
common/main/valptridx.tcc:36:182: error: format '%u' expects argument of type 'unsigned int', but argument 7 has type 'std::size_t {aka long long unsigned int}' [-Werror=format=]
This occurs even though the processed text uses %I64u (which is correct
for a `long long unsigned int`), not %u as shown in the error message.
static void prepare_report(const char *const filename, const unsigned lineno, const void *const array_base, const long supplied_index, const void *const expected_pointer, const void *const actual_pointer, char (&buf)[report_buffer_size], const std::size_t array_size)
{
snprintf(buf, sizeof(buf), "%s:%u: " "pointer/index mismatch:" " base=%p size=%" "I64u" " index=%li expected=%p actual=%p", filename, lineno, array_base, array_size, supplied_index, expected_pointer, actual_pointer);
}
In practice, all such sizes will fit in `unsigned int` because they are
the dimension of an array of large structures. Switch all platforms to
use `unsigned long`, which works everywhere and is at least as big as
`unsigned int`. Using `unsigned long` produces the same size as
`std::size_t` on all platforms other than Win64, where `unsigned long`
is only 32 bits due to the strange LLP64 model Microsoft picked.
Commit b32298df5a ("Rewrite powerup cap
code to centralize logic") centralized powerup cap code in the
powerup_cap_state class.
Commit 901a554e96 ("New powerup management
code: Addeed functions and packet type to ...") removed all use of
powerup_cap_state, but left the dead implementation present.
Commit 479f5ed584 ("Fix 'format specifies
type 'unsigned short' but the argument has type 'unsigned char''
warning") switched the already dead (but still compiled) code from %hu
to %hhu to fix a warning on OS X. Although the commit was written by
Chris, it was my suggestion to use %hhu. I neglected to test Windows
before suggesting it, so the change went in even though Windows does not
accept %hhu; this broke the Windows build. Fortunately, the code had
been dead for 11 months when the change was made, so the fix for Windows
is to remove the long dead code.
Descent 1 has no headlight powerup. Code to read headlights was
incorrectly added in 357e1b0144, but no code was added to write
headlights, so the Descent 1 lighting code checked for headlights that
never existed. Guard the headlight global variables and the associated
logic with if(D2).
Fixes: 357e1b0144 ("Made lighting code work with actual RGB values and added feature to let certain objects emit colored dynamic light as well as let mine flash red when control center destroyed (OpenGL-only at the moment)")
Type `SyncGLMethod` was defined conditional on DXX_USE_OGL, but header
`common/include/ogl_sync.h` used `SyncGLMethod` unconditionally. This
works fine in the normal build since SDL builds never include
`common/include/ogl_sync.h`, but broke the check_header_includes=1 test
since that compiles `common/include/ogl_sync.h` even for SDL builds.
Wrap type `ogl_sync` in `#if DXX_USE_OGL` to hide it from the
check_header_includes=1 test in SDL mode.
Expose sphere_intersects_wall and call it directly from
boss_fits_in_seg, so that boss_fits_in_seg does not need to modify the
position and segment of the boss during the test.
If boss has teleported before, even before a loaded state was saved, play the boss looping sound immediately when loading the saved game (if near the boss). Resolves issue #326.
clang becomes confused trying to determine which vm_distance_squared
constructor to use for a literal input of 0x7fffffffffffffff, even
though the size of the input requires it to be `long` and only one
constructor can take a `long`. Switch from an explicit
0x7fffffffffffffff to the symbolic constant INT64_MAX, which has the
same value, but a platform-appropriate suffix to force the compiler to
pick the right type.
For general clarity, switch some other instances of integer maximum
literals to symbolic constants of the same value.
This commit has no effect on the generated code (except for changes to
line numbers).
Reported-by: kreatordxx <https://github.com/dxx-rebirth/dxx-rebirth/pull/324>
Fixes: 17208cca79 ("Disallow int for vm_distance_squared")
When objp is nullptr, ai_door_is_openable assumes Buddy_objnum is a
valid object number, but this assumption is not guaranteed to be true.
When it is false, the game crashes. This crash can be triggered by a
brain robot trying to make nearby robots snipe.
Fix the crash by passing the robot of interest.
Reported-by: Yarn <http://www.dxx-rebirth.com/frm/index.php/topic,2165.0.html>
When using `gcc -fsanitize=undefined`, the compiler proves trivial
results, so `DXX_CONSTANT_TRUE` is defined. It then fails to prove that
`DXX_CONSTANT_TRUE(m_state == checked)` is false, causing a compile-time
error. Relax the check to occur only when it can prove `m_state` equal
to a disallowed value, rather than when it cannot prove `m_state` equal
to an allowed value.
Move the preprocessor guard so that the runtime check is always visible.
Optimizing compilers can still eliminate that check at compile-time when
it provably never fails.
Macro LINE_SPACING previously used global grd_curcanv implicitly.
Change it to take a canvas argument. Change all callers to pass
grd_curcanv, so that usage is explicit.
As a macro, it always refers to the global grd_curcanv. This interferes
with converting canvas handling to be an argument. Expand GHEIGHT so
that uses of grd_curcanv can be changed individually.
As a macro, it always refers to the global grd_curcanv. This interferes
with converting canvas handling to be an argument. Expand GWIDTH so
that uses of grd_curcanv can be changed individually.
Movement handling has an ugly hack that tries to grab powerups near the
console player, but it reuses general collision handling and fails to
check whether the player is alive.
Add a liveness check. Place the check so that it happens once, before
the objects are scanned, rather than being needlessly repeated for every
object.
Refactor the collision code to let the movement hack skip the parts it
does not need.
Reported-by: ryusei117 <https://github.com/dxx-rebirth/dxx-rebirth/issues/302#issuecomment-275816259>
PCH mode causes the Valgrind-wrapper header to be included in places
it is not meant to be used, which leads to spurious compiler errors.
PCH mode causes the Valgrind-wrapper __real_* stub functions to see
the physfsx.h PHYSFS macros, which also causes errors.
Fortunately, both cases can be easily fixed.
Add preprocessor guards to the Valgrind-wrapper header to cause it to
compile out when the PCH phase runs. It has no include guard, so it
will be rescanned with the proper macros when the two consuming files
are built normally.
Modify the Valgrind-wrapper __real_* stub functions to use
the standard macro avoidance trick so that they do not call the
physfsx.h PHYSFS macros.
Kreator proposed restoring the Descent 2 cheat that grants homing
capability to all weapons. This commit implements that proposition,
with some changes to the implementation details.
Based-on-patch-by: Chris Taylor <chris@icculus.org>
Requested-by: Chris Taylor <https://github.com/dxx-rebirth/dxx-rebirth/pull/318>
By design, valptridx will throw an exception on invalid input. This is
better than silently permitting invalid input to corrupt program state.
Past releases blindly trusted that multiplayer peers would not send
invalid input. Conversion to the valptridx design eliminated the
undefined behavior when peers send invalid input, but still allowed
multiplayer peers to remotely crash the game by sending invalid inputs.
Add a mechanism to trap invalid inputs and gracefully ignore those
messages. This may cause game consistency issues, but will not allow
data corruption.
Contains 2 calls - to obj_create and init_ai_object. For safety reasons and tidiness compared to using obj_create directly. The call to init_ai_object in recreate_thief was already redundant.
All releases to date have a bug where they treat certain segment number
fields as an int, not a segment number. Storing segment_none (0xffff)
into the save file causes affected releases to crash in various places
because it fails to recognize that this is segment_none.
Current code correctly treats segment_none as a non-segment and works
correctly without this hack. The hack is only required to get past
releases to work correctly after loading a saved game written by current
code.
Use std::equal_range to find the upper and lower bounds in a single
binary search, rather than relying on a linear search to find the first
sought element.
Some bitblt code had guards of the form:
#if A
xxx
#if !A
yyy
#endif
zzz
#endif
If A is true, !A is false, so the inner block can never be included.
Delete it.
In multi_do_frame(), replace call to window_close(Game_wind) with returning window_event_result::close whenever multi_quit_game is true. Only using this return value where multi_do_frame() is directly called by GameProcessFrame(). multi_quit_game will only be set back to 0 when a new multi game is started.
Closing a window within its handler is problematic - it can result in an unstable state.
Replace call to window_close(Game_wind) with returning window_event_result::close to game_handler. Applies to when there is a failure in net_udp_level_sync(). Closing a window within its handler is problematic - it can result in an unstable state.
Replace call to window_close(Game_wind) with returning window_event_result::close to game_handler. Applies to whenever newdemo_stop_playback() is called. Closing a window within its handler is problematic - it can result in an unstable state.
`struct object_rw` is poisoned prior to initializing and sending it.
However, some fields are legitimately unininitialized (other than their
memset or poison value) at send time. Add and use a poison variant that
can clear those fields, without marking them unreadable.