Skip to content

Commit

Permalink
wzapi: check and process deferred object removals in more places
Browse files Browse the repository at this point in the history
These places include not only those which involve triggers upon
`droidUpdate()` inside the main execution sequence of the game
loop, but also those events that execute prior to and
after the main things in the game loop, e.g.:

* Level start.
* Load/Save game.
* Start playing videos.
* Render loop.

Some of these places may be just extra work and probably
won't have even a slight possibility of calling
`wzapi::removeObject` from inside them, but it's always
better to be safe than sorry.

Also, introduce a check for already-dead entries in
`processScriptQueuedObjectRemovals()` and skip them.

This is a way to deal with duplicate entries to ensure
we don't destroy a single object more than once.

These things can occur when, e.g., several units happen to
move near enough to an artifact lying on the ground, so that
they would pick up the artifact simultaneously within the same
game loop iteration (in the `checkLocalFeatures()` function).

In such case, each of these droids will trigger the
"artifact picked up" event, so JS handler (`cam_eventPickup`)
will be called multiple times for the same object, each trying
to place it into `scriptQueuedObjectRemovals()` list.

Signed-off-by: Pavel Solodovnikov <[email protected]>
  • Loading branch information
ManManson committed Apr 18, 2024
1 parent 41ec6c6 commit 2283c39
Show file tree
Hide file tree
Showing 8 changed files with 41 additions and 22 deletions.
3 changes: 2 additions & 1 deletion src/game.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@
#include "multigifts.h"
#include "wzscriptdebug.h"
#include "gamehistorylogger.h"
#include "wzapi.h"
#include <array>

#if defined(__clang__)
Expand Down Expand Up @@ -3379,7 +3380,7 @@ bool saveGame(const char *aFileName, GAME_TYPE saveType, bool isAutoSave)
size_t fileExtension;
char CurrentFileName[PATH_MAX] = {'\0'};

triggerEvent(TRIGGER_GAME_SAVING);
executeFnAndProcessScriptQueuedRemovals([]() { triggerEvent(TRIGGER_GAME_SAVING); });

ASSERT_OR_RETURN(false, aFileName && strlen(aFileName) > 4, "Bad savegame filename");
sstrcpy(CurrentFileName, aFileName);
Expand Down
5 changes: 3 additions & 2 deletions src/init.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@
#include "seqdisp.h"
#include "version.h"
#include "hci/teamstrategy.h"
#include "wzapi.h"

#include <algorithm>
#include <unordered_map>
Expand Down Expand Up @@ -1895,7 +1896,7 @@ bool stageThreeInitialise()

if (getLevelLoadType() == GTYPE_SAVE_MIDMISSION || getLevelLoadType() == GTYPE_SAVE_START)
{
triggerEvent(TRIGGER_GAME_LOADED);
executeFnAndProcessScriptQueuedRemovals([]() { triggerEvent(TRIGGER_GAME_LOADED); });
}
else
{
Expand All @@ -1907,7 +1908,7 @@ bool stageThreeInitialise()
triggerEventCheatMode(true);
}

triggerEvent(TRIGGER_GAME_INIT);
executeFnAndProcessScriptQueuedRemovals([]() { triggerEvent(TRIGGER_GAME_INIT); });
playerBuiltHQ = structureExists(selectedPlayer, REF_HQ, true, false);
}

Expand Down
26 changes: 12 additions & 14 deletions src/loop.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -491,14 +491,6 @@ void countUpdate(bool synch)
}
}

template <typename Fn>
static void executeFnAndProcessScriptQueuedRemovals(Fn fn)
{
ASSERT(wzapi::scriptQueuedObjectRemovals().empty(), "Leftover script-queued object removals detected!");
fn();
wzapi::processScriptQueuedObjectRemovals();
}

static void gameStateUpdate()
{
WZ_PROFILE_SCOPE(gameStateUpdate);
Expand Down Expand Up @@ -586,7 +578,7 @@ static void gameStateUpdate()

missionTimerUpdate();

proj_UpdateAll();
executeFnAndProcessScriptQueuedRemovals([]() { proj_UpdateAll(); });

for (FEATURE *psCFeat : apsFeatureLists[0])
{
Expand Down Expand Up @@ -710,10 +702,16 @@ GAMECODE gameLoop()
NETflush(); // Make sure that we aren't waiting too long to send data.
}

unsigned before = wzGetTicks();
GAMECODE renderReturn = renderLoop();
pie_ScreenFrameRenderEnd(); // must happen here for proper renderBudget calculation
unsigned after = wzGetTicks();
unsigned before, after;
GAMECODE renderReturn;
executeFnAndProcessScriptQueuedRemovals([&before, &after, &renderReturn]()
{
before = wzGetTicks();
renderReturn = renderLoop();
pie_ScreenFrameRenderEnd(); // must happen here for proper renderBudget calculation
after = wzGetTicks();
});


#if defined(__EMSCRIPTEN__)
lastRenderDelta = (after - before);
Expand Down Expand Up @@ -769,7 +767,7 @@ void videoLoop()
{
displayGameOver(getScriptWinLoseVideo() == PLAY_WIN, false);
}
triggerEvent(TRIGGER_VIDEO_QUIT);
executeFnAndProcessScriptQueuedRemovals([]() { triggerEvent(TRIGGER_VIDEO_QUIT); });
}
}
}
Expand Down
3 changes: 2 additions & 1 deletion src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@
#include "wzcrashhandlingproviders.h"
#include "wzpropertyproviders.h"
#include "3rdparty/gsl_finally.h"
#include "wzapi.h"

#if defined(WZ_OS_UNIX)
# include <signal.h>
Expand Down Expand Up @@ -987,7 +988,7 @@ static void startGameLoop()
{
addMissionTimerInterface();
}
triggerEvent(TRIGGER_START_LEVEL);
executeFnAndProcessScriptQueuedRemovals([]() { triggerEvent(TRIGGER_START_LEVEL); });
screen_disableMapPreview();

if (!bMultiPlayer && getCamTweakOption_AutosavesOnly())
Expand Down
8 changes: 6 additions & 2 deletions src/mission.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@
#include "lib/framework/wztime.h"
#include "keybind.h"
#include "campaigninfo.h"
#include "wzapi.h"

#define IDMISSIONRES_TXT 11004
#define IDMISSIONRES_LOAD 11005
Expand Down Expand Up @@ -2113,7 +2114,10 @@ void intUpdateTransporterTimer(WIDGET *psWidget, const W_CONTEXT *psContext)
if (psTransporter->action == DACTION_TRANSPORTWAITTOFLYIN)
{
missionFlyTransportersIn(selectedPlayer, false);
triggerEvent(TRIGGER_TRANSPORTER_ARRIVED, psTransporter);
executeFnAndProcessScriptQueuedRemovals([psTransporter]()
{
triggerEvent(TRIGGER_TRANSPORTER_ARRIVED, psTransporter);
});
}
}
}
Expand Down Expand Up @@ -2859,7 +2863,7 @@ void missionTimerUpdate()
if ((SDWORD)(gameTime - mission.startTime) > mission.time)
{
//the script can call the end game cos have failed!
triggerEvent(TRIGGER_MISSION_TIMEOUT);
executeFnAndProcessScriptQueuedRemovals([]() { triggerEvent(TRIGGER_MISSION_TIMEOUT); });
}
}
}
Expand Down
3 changes: 2 additions & 1 deletion src/transporter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
#include "visibility.h"
#include "multiplay.h"
#include "hci/groups.h"
#include "wzapi.h"

//#define IDTRANS_FORM 9000 //The Transporter base form
#define IDTRANS_CLOSE 9002 //The close button icon
Expand Down Expand Up @@ -1280,7 +1281,7 @@ void processLaunchTransporter()
//set the data for the transporter timer
widgSetUserData(psWScreen, IDTRANTIMER_DISPLAY, (void *)psCurrTransporter);

triggerEvent(TRIGGER_TRANSPORTER_LAUNCH, psCurrTransporter);
executeFnAndProcessScriptQueuedRemovals([]() { triggerEvent(TRIGGER_TRANSPORTER_LAUNCH, psCurrTransporter); });
}
}
}
Expand Down
7 changes: 6 additions & 1 deletion src/wzapi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4591,7 +4591,7 @@ wzapi::QueuedObjectRemovalsVector& wzapi::scriptQueuedObjectRemovals()
{
static QueuedObjectRemovalsVector instance = []()
{
static constexpr size_t initialCapacity = 16;
static constexpr size_t initialCapacity = 32;
QueuedObjectRemovalsVector ret;
ret.reserve(initialCapacity);
return ret;
Expand All @@ -4605,6 +4605,11 @@ void wzapi::processScriptQueuedObjectRemovals()
for (auto& objWithSfxFlag : queuedObjRemovals)
{
BASE_OBJECT* psObj = objWithSfxFlag.first;
if (psObj->died)
{
debug(LOG_MSG, "Object %p is already dead, not processing", psObj);

Check failure on line 4610 in src/wzapi.cpp

View workflow job for this annotation

GitHub Actions / Fedora :LATEST [GCC]

format '%p' expects argument of type 'void*', but argument 5 has type 'BASE_OBJECT*' [-Werror=format=]

Check failure on line 4610 in src/wzapi.cpp

View workflow job for this annotation

GitHub Actions / Fedora :LATEST [GCC -m32]

format '%p' expects argument of type 'void*', but argument 5 has type 'BASE_OBJECT*' [-Werror=format=]

Check failure on line 4610 in src/wzapi.cpp

View workflow job for this annotation

GitHub Actions / Arch :LATEST [Clang]

format specifies type 'void *' but the argument has type 'BASE_OBJECT *' [-Werror,-Wformat-pedantic]

Check failure on line 4610 in src/wzapi.cpp

View workflow job for this annotation

GitHub Actions / Arch :LATEST [GCC]

format ‘%p’ expects argument of type ‘void*’, but argument 5 has type ‘BASE_OBJECT*’ [-Werror=format=]

Check failure on line 4610 in src/wzapi.cpp

View workflow job for this annotation

GitHub Actions / Alpine :LATEST [GCC]

format '%p' expects argument of type 'void*', but argument 5 has type 'BASE_OBJECT*' [-Werror=format=]

Check failure on line 4610 in src/wzapi.cpp

View workflow job for this annotation

GitHub Actions / arm64 [LLVM_MINGW]

format specifies type 'void *' but the argument has type 'BASE_OBJECT *' [-Werror,-Wformat-pedantic]

Check failure on line 4610 in src/wzapi.cpp

View workflow job for this annotation

GitHub Actions / x86 [LLVM_MINGW]

format specifies type 'void *' but the argument has type 'BASE_OBJECT *' [-Werror,-Wformat-pedantic]

Check failure on line 4610 in src/wzapi.cpp

View workflow job for this annotation

GitHub Actions / Ubuntu 20.04 [Clang]

format specifies type 'void *' but the argument has type 'BASE_OBJECT *' [-Werror,-Wformat-pedantic]

Check failure on line 4610 in src/wzapi.cpp

View workflow job for this annotation

GitHub Actions / x64 [LLVM_MINGW]

format specifies type 'void *' but the argument has type 'BASE_OBJECT *' [-Werror,-Wformat-pedantic]

Check failure on line 4610 in src/wzapi.cpp

View workflow job for this annotation

GitHub Actions / Ubuntu 22.04 [Clang]

format specifies type 'void *' but the argument has type 'BASE_OBJECT *' [-Werror,-Wformat-pedantic]

Check failure on line 4610 in src/wzapi.cpp

View workflow job for this annotation

GitHub Actions / Ubuntu 20.04 [GCC]

format '%p' expects argument of type 'void*', but argument 5 has type 'BASE_OBJECT*' [-Werror=format=]

Check failure on line 4610 in src/wzapi.cpp

View workflow job for this annotation

GitHub Actions / Ubuntu 22.04 [GCC]

format '%p' expects argument of type 'void*', but argument 5 has type 'BASE_OBJECT*' [-Werror=format=]
continue;
}
if (objWithSfxFlag.second)
{
switch (psObj->type)
Expand Down
8 changes: 8 additions & 0 deletions src/wzapi.h
Original file line number Diff line number Diff line change
Expand Up @@ -1156,4 +1156,12 @@ namespace wzapi
void processScriptQueuedObjectRemovals();
} // namespace wzapi

template <typename Fn>
static void executeFnAndProcessScriptQueuedRemovals(Fn fn)
{
ASSERT(wzapi::scriptQueuedObjectRemovals().empty(), "Leftover script-queued object removals detected!");
fn();
wzapi::processScriptQueuedObjectRemovals();
}

#endif

0 comments on commit 2283c39

Please sign in to comment.