1
0
Fork 0
mirror of https://github.com/TerryCavanagh/VVVVVV.git synced 2024-11-18 17:09:41 +01:00
Commit graph

2257 commits

Author SHA1 Message Date
Misa
fe8d163041 Fix reading uninitialized memory when creating Menu::levellist
Valgrind reported this.

The error here is that the buffer here is only guaranteed to be
initialized up until (and including) the null-terminator, by
SDL_snprintf(). Iterating over the entire allocated buffer is bad and I
should feel bad as the girl who wrote this code; doing that reads
uninitialized memory and passes it to SDL_tolower().

As a bonus, the iterator increment is now a preincrement instead of a
postincrement.
2021-02-15 23:07:35 -05:00
Misa
3226d4f312 Free loaded file in editorclass::getLevelMetadata()
This fixes memory leaking every single time a file gets loaded(!) when
the list of custom levels gets loaded(!!!), which Valgrind reports. This
memory leak is completely my bad; 2.2 properly frees the loaded file,
and VCE uses an std::unique_ptr - which I decided to ignore and not
think about why it would be there.

It's safe to do this free after uMem gets copied into std::string;
although, in the future, I *am* thinking about refactoring this function
(and the tag finder function) to not use std::strings, and I'll have to
be careful to make sure that the memory management with the file is
correct when I do so.
2021-02-15 23:07:35 -05:00
Misa
16fef54ae1 Pass 1 to Mix_LoadMUS_RW() in MusicTrack::MusicTrack()
This makes the freesrc argument of Mix_LoadMUS_RW() 1 instead of 0. If
the argument is nonzero, then the passed SDL_RWops will be automatically
freed when m_music is freed, too.

I don't know why this was 0 before. Setting it to 1 fixes a memory leak
that Valgrind reports (which turns into an actual leak every time custom
assets are mounted or unmounted).
2021-02-15 23:07:35 -05:00
Misa
8052f61cef Check if file can't be loaded in SoundTrack::SoundTrack()
This adds a check that the pointer passed to
FILESYSTEM_loadFileToMemory() isn't NULL, and if it is, just returns
early in the function, instead of continuing later and producing a
different, slightly-misleading error message.
2021-02-15 23:07:35 -05:00
Misa
f401cc6230 Unconditionally call FILESYSTEM_freeMemory() in SoundTrack constructor
Previously, it was guarded behind a check for the length, which is... I
guess still perfectly fine behavior, but there's no reason to have a
length check here; FILESYSTEM_freeMemory() uses SDL_free(), which does a
check that the pointer passed is non-NULL (the pointer that is passed
here, despite not being initialized upon declaration, is guaranteed to
be initialized by FILESYSTEM_loadFileToMemory() anyway, so).
2021-02-15 23:07:35 -05:00
Misa
b19daebeef Bail for all SDL_malloc() failures
Following Ethan's example of bailing (calling VVV_exit()) if
binaryBlob::unPackBinary() couldn't allocate memory, I've searched
through and found every SDL_malloc(), then made sure that if it returned
NULL, the caller would bail (because you can't do much when you're out
of memory).

There should probably be an error message printed when the process is
out of memory, but unPackBinary() doesn't print an error message for
being out of memory, so this can probably be added later. (Also we don't
really have a logging system, I'd like to have something like that added
in first before adding more messages.)

Also, this doesn't account for any allocators used by STL stuff, but
we're working on removing the STL, and allocation failure just results
in an abort anyway, so there's not really a problem there.
2021-02-15 23:07:35 -05:00
Misa
8aa5bb8aab Clean up all program close paths to use VVV_exit()
Wow, there are a lot of these. All of these exit paths now use
VVV_exit() instead, which attempts to save unlock.vvv and settings.vvv,
and also frees all resources so Valgrind is happy. This is a good thing,
because previously unlock.vvv/settings.vvv wouldn't be written to if we
decided to bail for a given reason.
2021-02-15 23:07:35 -05:00
Misa
de1e773b7f Remove <string.h> #include from main.cpp
We no longer use libc string functions, instead preferring SDL's; this
unused include should be removed.
2021-02-15 23:07:35 -05:00
Misa
d39fe96cf2 Move Script.cpp <limits.h> #include to proper place
It should be between the include of the corresponding header file for
the source file (Script.h) and the includes of other local header files
(the files that are specific to this codebase only); this is the
convention that includes in all other source files follow.

However, it seems like I misplaced this, so I'm fixing it now.
2021-02-15 23:07:35 -05:00
Misa
4964cb7bc3 Add VVV_exit()
This is just a function that calls the cleanup() in main.cpp, as well as
calls exit().

I would have liked to use SDL_ExitProcess() here, because that function
has ifdefs for different runtime environments. But alas, it's an
internal function and isn't exported. Ah well; exit() seems to be fine
anyway.
2021-02-15 23:07:35 -05:00
Misa
efbaeeffde Clean up all leftover resources in cleanup()
If there's a resource that doesn't otherwise need to be cleaned up and
is still alive upon program shutdown, then it should go in cleanup().

This cleans up Screen, GraphicsResources, Graphics buffers, Graphics
tiles, and musicclass audio upon program shutdown.

Even we technically don't NEED to clean these resources up ourselves
(the kernel is going to get rid of all of it anyway, else it'd be a
security problem), I'm doing this because otherwise Valgrind will
complain about these, and then it'd be difficult to see which memory
leaks are real and which are just "well this isn't really a leak but you
haven't freed this thing when the process exited, and that's technically
what a memory leak is".

These are all resources whose cleanup functions can be safely called
even if they haven't initialized anything yet.
2021-02-15 23:07:35 -05:00
Misa
39e316828e Add NULL guards to Game::savestats() and savesettings()
This is so those functions can safely be called when
graphics.screenbuffer is NULL.
2021-02-15 23:07:35 -05:00
Misa
1f1b39a77a Free base tilesheet image after processing it
This isn't a memory leak (not even Valgrind complains), because it gets
properly cleaned up in GraphicsResources::destroy(). Still, it's memory
that is just laying around not being used, and in the name of
deallocating things as soon as you no longer need them, we should
deallocate the base tilesheet images after we split all of them into
tiles.

This reduces the memory cost of all tilesheet images by half, since we
were essentially keeping around duplicates for nothing; this doesn't
really have much of an impact with conventional tilesheet sizes, since
they're usually small enough, but since 2.3 allowed for tilesheet images
of any size, this is a pretty big deal for really big tilesheet images.

It's okay to do this, even though they also get freed in
GraphicsResources::destroy(), because SDL_FreeSurface() does a NULL
check on the pointer passed to it, and we set the pointer to NULL after
freeing the surfaces.
2021-02-15 23:07:35 -05:00
Misa
6077015fdc Guard PHYSFS_deinit() with PHYSFS_isInit()
A quick glance at PhysFS source code will show that PhysFS will bail if
PHYSFS_deinit() is called if it's not initialized.

"Bail" here just means setting an error code and returning early, so
it's not that bad. Still, it's the principle of the thing, and I just
want to ensure that FILESYSTEM_deinit() can be safely called no matter
if the filesystem hasn't initialized yet; having an error set by PhysFS
kind of taints the whole safety thing, even if it does nothing wrong,
no?

(although, speaking of which, we should be handling all errors by
PhysFS, but that's for later...)
2021-02-15 23:07:35 -05:00
Misa
951e1653a6 Move cleanup code to separate function
I will need to re-use this code, so it's best that it not be
copy-pasted.
2021-02-15 23:07:35 -05:00
Misa
de26596d54 Fix FIXME comments with outdated referents in Screen.cpp
These FIXME comments are still correct about code duplication, but
they're incorrect about where exactly the original code is after the
original code got moved around. So I've fixed them to refer to the
correct locations.

We really should get around to de-duplicating the code mentioned in
these comments...
2021-02-15 23:07:35 -05:00
Misa
a3ad7b73f3 Add Screen::destroy()
In order to have squeaky-clean memory management, we'll need to clean up
all the things that Screen allocates. This is the function to call to do
so.
2021-02-15 23:07:35 -05:00
Misa
7f3ebda8ea Clear musicWriteBlob after writing BinaryMusic.vvv
Since musicWriteBlob is a temporary object that gets destroyed at the
end of musicclass::init(), in order to make sure we don't leak memory
and lose all the pointers to the blocks we just allocated in
musicWriteBlob, we need to call its clear() method after writing
BinaryMusic.vvv.
2021-02-15 23:07:35 -05:00
Misa
77748f29f9 Separate musicReadBlob into mmmmmm_blob and pppppp_blob
musicReadBlob was used for both MMMMMM and PPPPPP soundtracks. This
causes a memory leak if you have mmmmmm.vvv installed, because the
pointers holding each allocated block of MMMMMM would be lost when
PPPPPP got loaded. Valgrind complains about this memory leak.

This is in contrast to 2.2 and previous behavior, where musicReadBlob
was only a temporary object instead of being held in musicclass.
However, this wasn't really a memory leak (moreso something that just
didn't get cleaned up when closing the game), but it did get turned into
a leak when per-level assets mounting and unmounting got introduced in
2.3 (loading a level with custom assets after starting the game with an
mmmmmm.vvv, or exiting out of a level that had an mmmmmm.vvv, would
cause the game to leak memory). Leo recognized this, and moved
musicReadBlob onto musicclass in a separate 2.3 PR, but either he didn't
think about what was happening here too closely, or he didn't use
Valgrind, because he forgot about the memory leak caused by re-using the
same binaryBlob for PPPPPP and MMMMMM.

So instead, just use two different binaryBlob objects for MMMMMM and
PPPPPP. That way, no memory leaks happen.
2021-02-15 23:07:35 -05:00
Misa
f39174b3e3 Refactor TRACK_NAMES to take in a blob parameter
I'm going to introduce another binaryBlob object in to the mix, and I
want to be able to re-use an existing FOREACH_TRACK #define without
having to copy-paste it again. So, TRACK_NAMES now takes in a blob
parameter, which will be passed to the temporary FOREACH_TRACK #define.
2021-02-15 23:07:35 -05:00
Misa
0ea1a0e28e Move musicclass cleanup to separate function musicclass::destroy()
This removes the music cleanup code from musicclass::init(), and
requires that we also call destroy() in Graphics::reloadresources().

This is because we'll need to re-use the musicclass cleanup code
elsewhere, and we don't want to copy-paste the cleanup code. Or at
least, I don't (but I'm not a game dev, game devs copy-paste all the
friggin' time).
2021-02-15 23:07:35 -05:00
Misa
b3679ce1e5 Fix brace style of Graphics::font_idx()
This really should be next-line brace, as is (most of) the rest of the
codebase.
2021-02-15 23:07:35 -05:00
Misa
a505059719 Move Graphics buffer creation to new func create_buffers()
It doesn't feel quite write leaving all the buffer creation code in
main(), even though it's perfectly okay to do so and it doesn't result
in any memory mismanagement that Valgrind can report; so I'm factoring
all of it out to a separate function, Graphics::create_buffers().

As a bonus, we no longer have to keep qualifying with `graphics.` in the
buffer creation code, which is nice.
2021-02-15 23:07:35 -05:00
Misa
5595bb0964 Add Graphics::destroy_buffers()
These destroy all the buffers that are created on the Graphics class.
Since these buffers can't be created at the same time as the rest of
Graphics is (due to the fact that they require knowing the pixel format
of the game screen), they can't be destroyed at the same as the rest of
Graphics is, either.
2021-02-15 23:07:35 -05:00
Misa
3fe1870b32 Move Graphics cleanup to new function Graphics::destroy()
This makes it so this cleanup code can be re-used without copy-pasting
it over and over again.
2021-02-15 23:07:35 -05:00
Misa
c955ce4380 Remove making new GraphicsResources object in reloadresources()
This is a very complicated way of zeroing out grphx (instead of using
SDL_zero()), which itself is completely unnecessary because grphx.init()
gets called immediately afterwards anyway.
2021-02-15 23:07:35 -05:00
Misa
1140f3cae3 Fix brace style of Graphics::reloadresources()
It should be next-line brace, not same-line brace. Even in a codebase
that uses same-line braces everywhere, I still prefer having next-line
braces inside functions (because they're at the top level, and you can't
next them). But regardless, this should still be next-line brace like
(most of) the rest of the codebase.
2021-02-15 23:07:35 -05:00
Misa
7ffafc8f4d Remove grphx.init() from Graphics::init()
grphx.init() is going to be called again (after grphx.destroy()) in
graphics.reloadresources() anyway, so there's no reason to have it here.
2021-02-15 23:07:35 -05:00
Misa
70b9ffe6a5 Tidy up binaryBlob initialization to use SDL_zeroa()
It's simpler and more concise than writing out the SDL_memset() in full,
which means you're less likely to screw up those lines of code.
2021-02-15 23:07:35 -05:00
Misa
bd97378862 Unconditionally free and zero in binaryBlob::clear()
The function previously conditionally freed a m_memblocks pointer if its
corresponding m_headers was valid. This makes me slightly worried about
the possibility that memory would be allocated, but the header would
still be marked as invalid.

I don't see how that could happen, but it's better to be safe than
sorry. SDL_free() does a guaranteed NULL pointer check (like most SDL
functions), so it's okay to pass NULL pointers to it.

Just to be sure, I'm also zeroing m_memblocks and m_headers after
freeing everything in the function.
2021-02-15 23:07:35 -05:00
Ethan Lee
47df6c9d66 Ignore resize events for unfocused windows 2021-02-14 22:51:07 -05:00
Misa
39abcfa8d9 Fix unreachable code warnings
MSVC complains about these, doesn't seem like GCC does. These can be
safely removed because they're unreachable, and they always follow a
case-switch or similar that has a default case which this code is a
duplicate of anyway. (Unless it isn't, in which case all the better to
remove it, becausee otherwise it looks misleading or confusing to casual
glances at the code.)
2021-02-14 16:48:27 -05:00
Misa
a2ba37a1a4 Fix out-of-bounds indexing with malformed XML entities in find_tag()
find_tag() would commit out-of-bounds indexing if someone made a level
file with malformed XML entity encodings in the metadata tags.

This would happen if the end of the string followed immediately after an
ampersand and hash, or if there wasn't a semicolon ending an XML entity.

Valgrind complains about these, so I've fixed it.
2021-02-11 19:45:33 -05:00
Misa
5de7c180ea Give static storage duration to radix in ss_toi()
Since the value is a const value that reads from an integer literal, it
should be static so we read it directly from storage instead of copying
it.
2021-02-08 09:44:29 -05:00
Misa
09841ef3a5 Don't mutate the decimal place in ss_toi()
This fixes a bug where "12" gets properly evaluated as 12, but "148"
gets evaluated as 1408. It's because `place` gets multiplied by `radix`
again, so `retval` gets multipled by 100 instead of 10.

There's no reason to have a `place` variable, so I've removed it
entirely. This simplifies the function a little bit.
2021-02-08 09:44:29 -05:00
Misa
adbae16666 Clean up script header check in editorclass::load()
The previous person who wrote this (a girl named Misa) clearly didn't
understand the reason why you couldn't compare line[line.length()-1]
directly to a string literal. It's because the former is a char, and the
latter is a pointer to a char. Both are ints, so it compiles fine, but
it doesn't do what you want it to.

Why not just make the latter a char instead of a string literal? Well,
because you can, but also I clearly didn't think this through earlier,
so that's why I didn't do it in the first place.

But this is fixed now.
2021-02-07 18:30:13 -05:00
Misa
4728f64e3a Remove commented-out "version 1" code from editorclass::load()
Search results for terms in this code, such as the split() function,
become annoying false-positives. So it's better to just remove it
entirely.
2021-02-07 18:30:13 -05:00
Misa
06cc5afe27 Pass input of UtilityClass::GCString() by const reference
This avoids an unnecessary copy of the input std::vector, since we don't
need to modify it for anything. This cuts down on unnecessary memory
operations.
2021-02-07 18:30:13 -05:00
Misa
46b0257cf1 Refactor ss_toi() to not use stringstreams
Apart from the std::string, this function no longer uses the STL.

ss_toi() is a simple function - it converts the input into an int,
taking as many digits as possible until it reaches a non-digit
character, at which point it stops. It's trivial to implement this
without the STL.

I could've used Int() here, but that would've required copying the
string to a temporary buffer to insert a null-terminator (we can't just
use a pointer-and-length data type either, the string functions don't
operate like that - one disadvantage of C strings!). Instead, I decided
to implement my own conversion to int here, because I don't think the
way we humans write our Arabic numerals is going to change anytime soon.

Also, the std::string input is now passed by const reference, instead of
making a copy - cutting down on unnecessary memory operations.
2021-02-07 18:30:13 -05:00
Misa
e1ae25b29b Use case-switch inside GCChar() instead of if-else tree
A case-switch here takes up less lines (at least with next-line brace
style) and doesn't repeat the 'button ==' part over and over.
2021-02-07 18:30:13 -05:00
Misa
eea37046ef Add constness to GCChar() input and switch position of asterisk
I personally like putting the asterisk with the type, because despite
the language parsing the asterisk as a part of the name, the pointer
part is clearly a part of the return type of the function. Also,
put constness here, to indicate that the input won't be modified inside
the function.
2021-02-07 18:30:13 -05:00
Misa
3cd18b337a Remove comment from GCChar()
This comment indicates that the function is used by
UtilityClass::GCString(). Which is unnecessary, because the reader can
trivially search for usages of GCChar in the file itself (the 'static'
preceding the function should be a good enough hint) - and if there
aren't any, then the reader will know the function is unused, whereas if
they read the comment, they would have been under the assumption that it
wasn't used. (There might also a compiler warning about it being unused,
which would be more confusing if the comment was still there.)

Point is, comments can get outdated, so removing the comment here makes
the code more self-documenting.
2021-02-07 18:30:13 -05:00
Misa
f9fa56a08a Remove unused cctype #include from UtilityClass.cpp
This header used to be needed for isxdigit(), but ever since we switched
to using our own VVV_isxdigit(), we don't need it anymore.
2021-02-07 18:30:13 -05:00
Misa
ef4418a7cb Remove commented-out code in Game::gameclock()
This code involves stringstreams, which causes a false-positive any time
I ripgrep for stringstream in the codebase.
2021-02-07 18:30:13 -05:00
Misa
3bc3b59378 Re-fix glitchy y-position when spawning onto a conveyor
This is a re-do of 942217f871 (#509), but
with a more conservative fix that only resets the player's newxp and
newyp when they respawn from a checkpoint or spawn in to the map.

Unlike the previous patch, if the player were to suddenly collide with a
conveyor or horizontally-moving platform during gameplay, their
y-position would revert back to the intended next y-position of the
previous frame. But this is the same behavior as before, I haven't ever
seen such a contrived situation come up, and this behavior is probably
more preferable for gameplay than actually going to the conveyor, so
it's fine.

I also decided to reset newxp here, and not just newyp, because while
resetting newyp seems to be enough, it's safer to also reset newxp (and
so future readers won't question why only newyp is reset but not newxp).

I tested this and it once again fixes the death loop issue from earlier,
while also still allowing for that Trench Warfare trick to be possible
(I tested it with the libTAS movie I mentioned in #606; it syncs fine).
There are no other known regressions resulting from this fix
(hopefully).
2021-02-01 19:51:55 -05:00
Misa
a406b99f4b Revert "Fix glitchy y-position when colliding with a conveyor"
This reverts commit 942217f871.

This fix (of a regression of a fix) has a regression where immediately
flipping off of horizontally-moving platforms or conveyors will no
longer provide you with a "boost" given certain vertical pixel
alignments.

The regression that this fix fixed will be fixed another way.

Fixes #606.
2021-02-01 19:51:55 -05:00
leo60228
b5ef10cae5 Consistently use Screen::GetWindowSize 2021-01-18 13:10:22 -05:00
leo60228
46d8599f62 Use SDL_GetRendererOutputSize instead of SDL_GetWindowSize
SDL_GetRendererOutputSize will always return the actual size, even in
some obscure HiDPI/macOS cases.
2021-01-18 13:10:06 -05:00
leo60228
d9fff2a8c3 Set SDL window as DPI-aware
This works on macOS, Wayland, and a few more esoteric platforms. X11
doesn't have a concept of DPI-awareness. Note that with this flag
SDL_GetWindowSize() isn't guaranteed to return the actual window size.
2021-01-18 13:09:47 -05:00
Misa
a32fc4a307 Improve support for retextured checkpoints and terminals in the editor
Retextured checkpoints have always been in the game, but clicking on
them in the editor would lead to them losing their retextured-ness. So,
checkpoints should be left alone if their p1 isn't either 0 or 1. Also,
they don't show up properly in the editor, so that's fixed, too.

Retextured and flipped terminals were added in 2.3, and show up properly
in-game, but don't properly show up in the editor, either. So now they
show up in the editor. Additionally, clicking on them will flip the
terminal as well, but only if its p1 is 0 or 1, just like checkpoints
now do.
2021-01-18 13:07:32 -05:00