Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions CMake/Dependencies.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
# and whether to link them statically.
include(functions/dependency_options)
include(functions/emscripten_system_library)
include(CheckCXXSourceCompiles)

if(EMSCRIPTEN)
emscripten_system_library("zlib" ZLIB::ZLIB USE_ZLIB=1)
Expand Down Expand Up @@ -275,3 +276,19 @@ if(GPERF)
find_package(Gperftools REQUIRED)
message("INFO: ${GPERFTOOLS_LIBRARIES}")
endif()

check_cxx_source_compiles("
extern char __bss_start;
extern char _end;
#include <cassert>
int main() {
assert(&__bss_start < &_end);
return 0;
}
" HAVE_LINKER_BSS_SYMBOLS)

if(HAVE_LINKER_BSS_SYMBOLS)
message(STATUS "Linker symbols `__bss_start` and `_end` are available")
else()
message(STATUS "Linker symbols `__bss_start` and `_end` are NOT available")
endif()
4 changes: 4 additions & 0 deletions CMake/functions/devilutionx_library.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,10 @@ function(add_devilutionx_library NAME)
target_compile_definitions(${NAME} PUBLIC ${DEVILUTIONX_DEFINITIONS})

set_relative_file_macro(${NAME})

if(HAVE_LINKER_BSS_SYMBOLS)
target_compile_definitions(${NAME} PUBLIC HAVE_LINKER_BSS_SYMBOLS)
endif()
endfunction()

# Same as add_devilutionx_library(${NAME} OBJECT).
Expand Down
3 changes: 2 additions & 1 deletion Source/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,8 @@ set(libdevilutionx_SRCS
utils/sdl_bilinear_scale.cpp
utils/sdl_thread.cpp
utils/surface_to_clx.cpp
utils/timer.cpp)
utils/timer.cpp
utils/mapping.cpp)

# These files are responsible for most of the runtime in Debug mode.
# Apply some optimizations to them even in Debug mode to get reasonable performance.
Expand Down
1 change: 1 addition & 0 deletions Source/DiabloUI/settingsmenu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,7 @@
auto *pOptionList = static_cast<OptionEntryListBase *>(pOption);
pOptionList->SetActiveListIndex(listIndex);
} break;
case OptionEntryType::String:
case OptionEntryType::Key:
case OptionEntryType::PadButton:
break;
Expand All @@ -221,7 +222,7 @@
return true;
}

void ItemSelected(size_t value)

Check warning on line 225 in Source/DiabloUI/settingsmenu.cpp

View workflow job for this annotation

GitHub Actions / tidy-check

Source/DiabloUI/settingsmenu.cpp:225:6 [readability-function-cognitive-complexity]

function 'ItemSelected' has cognitive complexity of 32 (threshold 25)
{
auto &vecItem = vecDialogItems[value];
int vecItemValue = vecItem->m_value;
Expand Down Expand Up @@ -337,7 +338,7 @@

} // namespace

void UiSettingsMenu()

Check warning on line 341 in Source/DiabloUI/settingsmenu.cpp

View workflow job for this annotation

GitHub Actions / tidy-check

Source/DiabloUI/settingsmenu.cpp:341:6 [readability-function-cognitive-complexity]

function 'UiSettingsMenu' has cognitive complexity of 136 (threshold 25)
{
backToMain = false;
shownMenu = ShownMenuType::Categories;
Expand Down Expand Up @@ -466,7 +467,7 @@
if (key == SDLK_UNKNOWN)
return false;
auto *pOptionKey = static_cast<KeymapperOptions::Action *>(selectedOption);
if (!pOptionKey->SetValue(key))

Check warning on line 470 in Source/DiabloUI/settingsmenu.cpp

View workflow job for this annotation

GitHub Actions / tidy-check

Source/DiabloUI/settingsmenu.cpp:470:31 [bugprone-narrowing-conversions]

narrowing conversion from 'uint32_t' (aka 'unsigned int') to signed type 'int' is implementation-defined
return false;
vecDialogItems[IndexKeyOrPadInput]->m_text = selectedOption->GetValueDescription();
return true;
Expand Down
7 changes: 6 additions & 1 deletion Source/controls/plrctrls.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@
return MyPlayer->position.future.ExactDistance(destination);
}

void FindItemOrObject()

Check warning on line 147 in Source/controls/plrctrls.cpp

View workflow job for this annotation

GitHub Actions / tidy-check

Source/controls/plrctrls.cpp:147:6 [readability-function-cognitive-complexity]

function 'FindItemOrObject' has cognitive complexity of 27 (threshold 25)
{
WorldTilePosition futurePosition = MyPlayer->position.future;
int rotations = 5;
Expand All @@ -153,7 +153,7 @@

for (WorldTilePosition targetPosition : searchArea) {
// As the player can not stand on the edge of the map this is safe from OOB
int8_t itemId = dItem[targetPosition.x][targetPosition.y] - 1;

Check warning on line 156 in Source/controls/plrctrls.cpp

View workflow job for this annotation

GitHub Actions / tidy-check

Source/controls/plrctrls.cpp:156:19 [bugprone-narrowing-conversions]

narrowing conversion from 'int' to signed type 'int8_t' (aka 'signed char') is implementation-defined
if (itemId < 0) {
// there shouldn't be any items that occupy multiple ground tiles, but just in case only considering positive indexes here

Expand Down Expand Up @@ -247,7 +247,7 @@
const int mx = monster.position.tile.x;
const int my = monster.position.tile.y;
if (dMonster[mx][my] == 0)
return false;

Check warning on line 250 in Source/controls/plrctrls.cpp

View workflow job for this annotation

GitHub Actions / tidy-check

Source/controls/plrctrls.cpp:250:10 [readability-simplify-boolean-expr]

redundant boolean literal in conditional return statement

return true;
}
Expand All @@ -259,7 +259,7 @@
bool canTalk = false;

for (size_t i = 0; i < ActiveMonsterCount; i++) {
int mi = ActiveMonsters[i];

Check warning on line 262 in Source/controls/plrctrls.cpp

View workflow job for this annotation

GitHub Actions / tidy-check

Source/controls/plrctrls.cpp:262:12 [bugprone-narrowing-conversions]

narrowing conversion from 'unsigned int' to signed type 'int' is implementation-defined
const Monster &monster = Monsters[mi];

if (!CanTargetMonster(monster))
Expand All @@ -283,10 +283,15 @@
}
}

void FindMeleeTarget()

Check warning on line 286 in Source/controls/plrctrls.cpp

View workflow job for this annotation

GitHub Actions / tidy-check

Source/controls/plrctrls.cpp:286:6 [readability-function-cognitive-complexity]

function 'FindMeleeTarget' has cognitive complexity of 45 (threshold 25)
{
bool visited[MAXDUNX][MAXDUNY] = { {} };
int maxSteps = 25; // Max steps for FindPath is 25
// Max steps for FindPath is 25
int maxSteps = 25;
if (*GetOptions().Gameplay.noMonstersAutoPursuing)
// Disable monster auto-pursuing
maxSteps = 0;

int rotations = 0;
bool canTalk = false;

Expand Down Expand Up @@ -419,7 +424,7 @@
CheckPlayerNearby();
}

void FindTrigger()

Check warning on line 427 in Source/controls/plrctrls.cpp

View workflow job for this annotation

GitHub Actions / tidy-check

Source/controls/plrctrls.cpp:427:6 [readability-function-cognitive-complexity]

function 'FindTrigger' has cognitive complexity of 42 (threshold 25)
{
int rotations = 0;
int distance = 0;
Expand Down Expand Up @@ -674,7 +679,7 @@
Size GetItemSizeOnSlot(int slot)
{
if (slot >= SLOTXY_INV_FIRST && slot <= SLOTXY_INV_LAST) {
int8_t ii = GetItemIdOnSlot(slot);

Check warning on line 682 in Source/controls/plrctrls.cpp

View workflow job for this annotation

GitHub Actions / tidy-check

Source/controls/plrctrls.cpp:682:15 [bugprone-narrowing-conversions]

narrowing conversion from 'int' to signed type 'int8_t' (aka 'signed char') is implementation-defined
if (ii != 0) {
Item &item = MyPlayer->InvList[ii - 1];
if (!item.isEmpty()) {
Expand Down
2 changes: 1 addition & 1 deletion Source/controls/touch/renderers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,7 @@ void VirtualDirectionPadRenderer::LoadArt()

void VirtualGamepadRenderer::Render(RenderFunction renderFunction)
{
if (CurrentEventHandler == DisableInputEventHandler)
if (CurrentEventHandler.handle == DisableInputEventHandler)
return;

primaryActionButtonRenderer.Render(renderFunction, buttonArt);
Expand Down
173 changes: 166 additions & 7 deletions Source/diablo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@
#include "utils/status_macros.hpp"
#include "utils/str_cat.hpp"
#include "utils/utf8.hpp"
#include "utils/shared.h"

#ifndef USE_SDL1
#include "controls/touch/gamepad.h"
Expand Down Expand Up @@ -486,6 +487,7 @@
return;

if (gmenu_presskeys(vkey) || CheckKeypress(vkey)) {
printf(">> %s:%d, not handled\n", __func__, __LINE__);
return;
}

Expand Down Expand Up @@ -841,12 +843,15 @@
nthread_ignore_mutex(true);
StartGame(uMsg);
assert(HeadlessMode || ghMainWnd);
EventHandler previousHandler = SetEventHandler(GameEventHandler);
EventHandler newHandler = { GameEventHandler, SDL_PollEvent };
EventHandler previousHandler = SetEventHandler(newHandler);
run_delta_info();
gbRunGame = true;
gbProcessPlayers = IsDiabloAlive(true);
gbRunGameResult = true;

printf(">> %s\n", __func__);

RedrawEverything();
if (!HeadlessMode) {
while (IsRedrawEverything()) {
Expand All @@ -869,6 +874,11 @@
unsigned run_game_iteration = 0;
#endif

/* Start a new level on new game start if specified */
if (uMsg == WM_DIABNEWGAME && *GetOptions().Gameplay.gameLevel)
StartNewLvl(*MyPlayer, interface_mode::WM_DIABNEXTLVL,
*GetOptions().Gameplay.gameLevel);

while (gbRunGame) {

#ifdef _DEBUG
Expand Down Expand Up @@ -937,7 +947,7 @@
RedrawEverything();
scrollrt_draw_game_screen();
previousHandler = SetEventHandler(previousHandler);
assert(HeadlessMode || previousHandler == GameEventHandler);
assert(HeadlessMode || previousHandler.handle == GameEventHandler);
FreeGame();

if (cineflag) {
Expand Down Expand Up @@ -1179,8 +1189,12 @@
if (*GetOptions().Graphics.showFPS)
EnableFrameCount();

init_create_window();
was_window_init = true;
if (!HeadlessMode) {
init_create_window();
was_window_init = true;
} else {
SDL_Init(SDL_INIT_EVENTS);
}

InitializeScreenReader();
LanguageInitialize();
Expand Down Expand Up @@ -1236,9 +1250,10 @@

DiabloInitScreen();

snd_init();

ui_sound_init();
if (!HeadlessMode) {
snd_init();
ui_sound_init();
}

// Item graphics are loaded early, they already get touched during hero selection.
InitItemGFX();
Expand Down Expand Up @@ -2524,6 +2539,9 @@
gbSelectProvider = true;
ReturnToMainMenu = false;

printf(">> %s: newgame=%d, single=%d\n", __func__,
bNewGame, bSinglePlayer);

do {
gbLoadGame = false;

Expand Down Expand Up @@ -2585,6 +2603,8 @@

int DiabloMain(int argc, char **argv)
{
setlinebuf(stdout);

Check failure on line 2606 in Source/diablo.cpp

View workflow job for this annotation

GitHub Actions / build

'setlinebuf': identifier not found

#ifdef _DEBUG
SDL_LogSetAllPriority(SDL_LOG_PRIORITY_DEBUG);
#endif
Expand All @@ -2608,6 +2628,12 @@
LuaInitialize();
if (!demo::IsRunning()) SaveOptions();

if (!(*GetOptions().Gameplay.shareGameStateFilename).empty()) {
// Share whole diablo state
shared::share_diablo_state(paths::ConfigPath() + "/" +
*GetOptions().Gameplay.shareGameStateFilename);
}

// Finally load game data
LoadGameArchives();

Expand Down Expand Up @@ -2740,8 +2766,10 @@
if (!gbIsMultiplayer) {
if (PauseMode != 0) {
PauseMode = 0;
printf(">> %s: resumed\n", __func__);
} else {
PauseMode = 2;
printf(">> %s: paused\n", __func__);
sound_stop();
qtextflag = false;
LastMouseButtonAction = MouseActionType::None;
Expand Down Expand Up @@ -3300,6 +3328,133 @@
return {};
}

static void
inject_sdl_events(uint32_t new_type)
{
static uint32_t prev_type;

unsigned int sdl_type, sdl_sym;
SDL_Scancode sdl_scan;
unsigned int diff, i;
SDL_Event event;

diff = prev_type ^ new_type;
prev_type = new_type;

for (i = 0; i < sizeof(diff) * 8; i++) {
unsigned int bit = (1 << i);
if (!(diff & bit))
continue;

sdl_type = (new_type & bit ? SDL_KEYDOWN : SDL_KEYUP);

if (bit == RING_ENTRY_KEY_LEFT) {
sdl_sym = SDLK_LEFT;
sdl_scan = SDL_SCANCODE_LEFT;
} else if (bit == RING_ENTRY_KEY_RIGHT) {
sdl_sym = SDLK_RIGHT;
sdl_scan = SDL_SCANCODE_RIGHT;
} else if (bit == RING_ENTRY_KEY_UP) {
sdl_sym = SDLK_UP;
sdl_scan = SDL_SCANCODE_UP;
} else if (bit == RING_ENTRY_KEY_DOWN) {
sdl_sym = SDLK_DOWN;
sdl_scan = SDL_SCANCODE_DOWN;
} else if (bit == RING_ENTRY_KEY_X) {
sdl_sym = SDLK_x;
sdl_scan = SDL_SCANCODE_X;
} else if (bit == RING_ENTRY_KEY_Y) {
sdl_sym = SDLK_y;
sdl_scan = SDL_SCANCODE_Y;
} else if (bit == RING_ENTRY_KEY_A) {
sdl_sym = SDLK_a;
sdl_scan = SDL_SCANCODE_A;
} else if (bit == RING_ENTRY_KEY_B) {
sdl_sym = SDLK_b;
sdl_scan = SDL_SCANCODE_B;
} else if (bit == RING_ENTRY_KEY_SAVE) {
sdl_sym = SDLK_F2;
sdl_scan = SDL_SCANCODE_F2;

if (sdl_type == SDL_KEYDOWN)
printf(">> %s: received SAVE\n", __func__);
} else if (bit == RING_ENTRY_KEY_LOAD) {
sdl_sym = SDLK_F3;
sdl_scan = SDL_SCANCODE_F3;

if (sdl_type == SDL_KEYDOWN)
printf(">> %s: received LOAD\n", __func__);
} else if (bit == RING_ENTRY_KEY_PAUSE) {
sdl_sym = SDLK_PAUSE;
sdl_scan = SDL_SCANCODE_PAUSE;

if (sdl_type == SDL_KEYDOWN)
printf(">> %s: received PAUSE\n", __func__);
} else {
/* Unknown key */
continue;
}

event.type = sdl_type;
event.key.keysym.sym = sdl_sym;
event.key.keysym.scancode = sdl_scan;
event.key.keysym.mod = KMOD_NONE;
event.key.repeat = 0;

if (SDL_PushEvent(&event) < 0) {
printf("Failed to push event: %s\n", SDL_GetError());
}
}
}

static void update_shared_state(void)
{
static bool release_keys;
struct ring_entry *entry;

if (MyPlayer)
// Do a static cast to avoid compiler warning that writing to
// an object with no trivial copy-assignment is not
// allowed. Please, FIXME.
memcpy(static_cast<void *>(&shared::player), MyPlayer, sizeof(shared::player));

// "Odd" phase of a tick before key injection. Two phases are
// needed for proper synchronization from the submitter's side,
// ensuring that the submitter knows exactly one full game tick
// has passed since the last key acceptance.
shared::game_ticks++;
// Prevent compiler from moving increment below the barrier
std::atomic_signal_fence(std::memory_order_seq_cst);

// On early start, the game state is not completely initialized,
// so incoming keys may not work. Delay keys processing. The
// number of ticks to delay was chosen empirically. Also ticks are
// multiplied by two, since there are two phases.
if (shared::game_ticks > 5*2) {
entry = ring_queue_get_entry_to_retreive(&shared::input_queue);
if (entry) {
uint32_t keys = entry->type;

release_keys = (keys & RING_ENTRY_F_SINGLE_TICK_PRESS);
keys &= ~RING_ENTRY_FLAGS;
inject_sdl_events(keys);
ring_queue_retrieve(&shared::input_queue);

/* Reply with key event */
entry = ring_queue_get_entry_to_submit(&shared::events_queue);
entry->type = keys;
ring_queue_submit(&shared::events_queue);
} else if (release_keys) {
release_keys = false;
inject_sdl_events(0);
}
}
// Prevent compiler from moving instructions below the barrier
std::atomic_signal_fence(std::memory_order_seq_cst);
// "even" phase of a tick once keys injected
shared::game_ticks++;
}

bool game_loop(bool bStartup)
{
uint16_t wait = bStartup ? sgGameInitInfo.nTickRate * 3 : 3;
Expand All @@ -3316,6 +3471,10 @@
if (!gbRunGame || !gbIsMultiplayer || demo::IsRunning() || demo::IsRecording() || !nthread_has_500ms_passed())
break;
}

if (!(*GetOptions().Gameplay.shareGameStateFilename).empty())
update_shared_state();

return true;
}

Expand Down
4 changes: 4 additions & 0 deletions Source/effects.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,10 @@ void effects_play_sound(SfxID id)

int GetSFXLength(SfxID nSFX)
{
if (!gbSndInited || !gbSoundOn) {
return 0;
}

TSFX &sfx = sgSFX[static_cast<int16_t>(nSFX)];
if (sfx.pSnd == nullptr)
sfx.pSnd = sound_file_load(sfx.pszName.c_str(),
Expand Down
8 changes: 4 additions & 4 deletions Source/engine/demomode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -683,13 +683,13 @@ bool GetRunGameLoop(bool &drawGame, bool &processInput)
return isGameTick;
}

bool FetchMessage(SDL_Event *event, uint16_t *modState)
bool FetchMessage(SDL_Event *event, uint16_t *modState, int (*poll)(SDL_Event *event))
{
if (CurrentEventHandler == DisableInputEventHandler)
if (CurrentEventHandler.handle == DisableInputEventHandler)
return false;

SDL_Event e;
if (SDL_PollEvent(&e) != 0) {
if (poll(&e) != 0) {
if (e.type == SDL_QUIT) {
*event = e;
return true;
Expand Down Expand Up @@ -741,7 +741,7 @@ void RecordMessage(const SDL_Event &event, uint16_t modState)
{
if (!gbRunGame || DemoRecording == nullptr)
return;
if (CurrentEventHandler == DisableInputEventHandler)
if (CurrentEventHandler.handle == DisableInputEventHandler)
return;
switch (event.type) {
case SDL_MOUSEMOTION:
Expand Down
Loading
Loading