diff --git a/Docs/CommonBase.dox b/Docs/Death.dox similarity index 97% rename from Docs/CommonBase.dox rename to Docs/Death.dox index 8adaa383..70ffe21f 100644 --- a/Docs/CommonBase.dox +++ b/Docs/Death.dox @@ -1,9 +1,8 @@ /** @file @brief Proxy definitions for documentation purposes - Definitions from this file are usually supplied via a compiler flag by CMake - or by including @ref CommonBase.h, which should be included everywhere. Don't - include this proxy file directly, it's not present in the include directory. + Definitions from this package are usually supplied via a compiler flag by CMake + or by including @ref CommonBase.h. */ namespace Death { @@ -140,6 +139,7 @@ namespace Death { @brief Windows RT target Defined if the library is built for Universal Windows Platform (Windows Store, Phone or Xbox). + In this case, @ref DEATH_TARGET_WINDOWS is also defined. */ #define DEATH_TARGET_WINDOWS_RT #undef DEATH_TARGET_WINDOWS_RT @@ -255,6 +255,24 @@ namespace Death { #define DEATH_TARGET_WASM #undef DEATH_TARGET_WASM +/** + @brief Whether the library is built for a 32-bit target + + Defined if the library is built for a 32-bit target. Not defined on 64-bit platforms. +*/ +#define DEATH_TARGET_32BIT +#undef DEATH_TARGET_32BIT + +/** + @brief Whether the platform defaults to big-endian + + Defined when the platform defaults to big-endian (such as HP/PA RISC, Motorola 68k, + Big-Endian MIPS, PowerPC and SPARC). Not defined on little-endian platforms (such + as x86 and ARM). This macro only reflects the usual architecture default. +*/ +#define DEATH_TARGET_BIG_ENDIAN +#undef DEATH_TARGET_BIG_ENDIAN + /** @brief GCC compiler diff --git a/Docs/Namespaces.dox b/Docs/Namespaces.dox index cce8565f..5e0e7298 100644 --- a/Docs/Namespaces.dox +++ b/Docs/Namespaces.dox @@ -53,7 +53,7 @@ This project is licensed under the terms of the [GNU General Public License v3.0 /** @file Shared/CommonBase.h @brief Basic definitions - Some configuration-specific and platform-specific definitions are also @ref CommonBase.dox "listed separately". + Some configuration-specific and platform-specific definitions, including `DEATH_TARGET_*`, are @ref Death.dox "listed separately". Some of them are supplied via a compiler flag by CMake, the rest of them also requires this header file to work properly. */ /** @file Shared/Common.h diff --git a/Sources/Jazz2/Actors/ActorBase.h b/Sources/Jazz2/Actors/ActorBase.h index 3d8060f2..808b9607 100644 --- a/Sources/Jazz2/Actors/ActorBase.h +++ b/Sources/Jazz2/Actors/ActorBase.h @@ -113,7 +113,7 @@ namespace Jazz2::Actors ExcludeSimilar = 0x8000000, }; - DEFINE_ENUM_OPERATORS(ActorState); + DEATH_ENUM_FLAGS(ActorState); /** @brief Description how to initialize an actor */ struct ActorActivationDetails { @@ -136,7 +136,7 @@ namespace Jazz2::Actors Force = 0x02 }; - DEFINE_ENUM_OPERATORS(MoveType); + DEATH_ENUM_FLAGS(MoveType); /** @brief Actor renderer type */ enum class ActorRendererType { diff --git a/Sources/Jazz2/Actors/Multiplayer/LocalPlayerOnServer.h b/Sources/Jazz2/Actors/Multiplayer/LocalPlayerOnServer.h index e6b536b8..dc720321 100644 --- a/Sources/Jazz2/Actors/Multiplayer/LocalPlayerOnServer.h +++ b/Sources/Jazz2/Actors/Multiplayer/LocalPlayerOnServer.h @@ -6,6 +6,7 @@ namespace Jazz2::Actors::Multiplayer { + /** @brief Local player in online session */ class LocalPlayerOnServer : public PlayerOnServer { DEATH_RUNTIME_OBJECT(PlayerOnServer); diff --git a/Sources/Jazz2/Actors/Multiplayer/PlayerOnServer.h b/Sources/Jazz2/Actors/Multiplayer/PlayerOnServer.h index b5e2834d..bdcdd934 100644 --- a/Sources/Jazz2/Actors/Multiplayer/PlayerOnServer.h +++ b/Sources/Jazz2/Actors/Multiplayer/PlayerOnServer.h @@ -6,6 +6,7 @@ namespace Jazz2::Actors::Multiplayer { + /** @brief Player in online session */ class PlayerOnServer : public Player { DEATH_RUNTIME_OBJECT(Player); diff --git a/Sources/Jazz2/Actors/Multiplayer/RemotablePlayer.h b/Sources/Jazz2/Actors/Multiplayer/RemotablePlayer.h index 7ff2d6fb..84432936 100644 --- a/Sources/Jazz2/Actors/Multiplayer/RemotablePlayer.h +++ b/Sources/Jazz2/Actors/Multiplayer/RemotablePlayer.h @@ -6,6 +6,7 @@ namespace Jazz2::Actors::Multiplayer { + /** @brief Remotable player in online session */ class RemotablePlayer : public Player { DEATH_RUNTIME_OBJECT(Player); diff --git a/Sources/Jazz2/Actors/Multiplayer/RemoteActor.h b/Sources/Jazz2/Actors/Multiplayer/RemoteActor.h index d8b4e1ab..9b7a61e5 100644 --- a/Sources/Jazz2/Actors/Multiplayer/RemoteActor.h +++ b/Sources/Jazz2/Actors/Multiplayer/RemoteActor.h @@ -6,6 +6,7 @@ namespace Jazz2::Actors::Multiplayer { + /** @brief Remote object in online session */ class RemoteActor : public ActorBase { DEATH_RUNTIME_OBJECT(ActorBase); diff --git a/Sources/Jazz2/Actors/Multiplayer/RemotePlayerOnServer.h b/Sources/Jazz2/Actors/Multiplayer/RemotePlayerOnServer.h index 505a4b3e..ebb5579a 100644 --- a/Sources/Jazz2/Actors/Multiplayer/RemotePlayerOnServer.h +++ b/Sources/Jazz2/Actors/Multiplayer/RemotePlayerOnServer.h @@ -6,6 +6,7 @@ namespace Jazz2::Actors::Multiplayer { + /** @brief Remote player in online session */ class RemotePlayerOnServer : public PlayerOnServer { DEATH_RUNTIME_OBJECT(PlayerOnServer); diff --git a/Sources/Jazz2/Actors/Player.cpp b/Sources/Jazz2/Actors/Player.cpp index 625af35a..7fdbee72 100644 --- a/Sources/Jazz2/Actors/Player.cpp +++ b/Sources/Jazz2/Actors/Player.cpp @@ -1517,7 +1517,7 @@ namespace Jazz2::Actors if (_activeShieldTime > (5.0f * FrameTimer::FramesPerSecond)) { _activeShieldTime -= (5.0f * FrameTimer::FramesPerSecond); } - float invulnerableTime = (_levelHandler->Difficulty() == GameDifficulty::Multiplayer ? 80.0f : 180.0f); + float invulnerableTime = (!_levelHandler->IsLocalSession() ? 80.0f : 180.0f); SetInvulnerability(invulnerableTime, InvulnerableType::Blinking); PlayPlayerSfx("HurtSoft"_s); } else { @@ -1585,7 +1585,7 @@ namespace Jazz2::Actors if (_activeShieldTime > (5.0f * FrameTimer::FramesPerSecond)) { _activeShieldTime -= (5.0f * FrameTimer::FramesPerSecond); } - float invulnerableTime = (_levelHandler->Difficulty() == GameDifficulty::Multiplayer ? 80.0f : 180.0f); + float invulnerableTime = (!_levelHandler->IsLocalSession() ? 80.0f : 180.0f); SetInvulnerability(invulnerableTime, InvulnerableType::Blinking); PlayPlayerSfx("HurtSoft"_s); } else { @@ -1635,7 +1635,7 @@ namespace Jazz2::Actors if (_activeShieldTime > (5.0f * FrameTimer::FramesPerSecond)) { _activeShieldTime -= (5.0f * FrameTimer::FramesPerSecond); } - float invulnerableTime = (_levelHandler->Difficulty() == GameDifficulty::Multiplayer ? 80.0f : 180.0f); + float invulnerableTime = (!_levelHandler->IsLocalSession() ? 80.0f : 180.0f); SetInvulnerability(invulnerableTime, InvulnerableType::Blinking); PlayPlayerSfx("HurtSoft"_s); } else { @@ -1659,7 +1659,7 @@ namespace Jazz2::Actors if (_activeShieldTime > (5.0f * FrameTimer::FramesPerSecond)) { _activeShieldTime -= (5.0f * FrameTimer::FramesPerSecond); } - float invulnerableTime = (_levelHandler->Difficulty() == GameDifficulty::Multiplayer ? 80.0f : 180.0f); + float invulnerableTime = (!_levelHandler->IsLocalSession() ? 80.0f : 180.0f); SetInvulnerability(invulnerableTime, InvulnerableType::Blinking); PlayPlayerSfx("HurtSoft"_s); } else { @@ -2631,7 +2631,7 @@ namespace Jazz2::Actors _keepRunningTime = 0.0f; _carryingObject = nullptr; - if (_lives > 1 || _levelHandler->Difficulty() == GameDifficulty::Multiplayer) { + if (_lives > 1 || !_levelHandler->IsLocalSession()) { if (_lives > 1 && _lives < UINT8_MAX) { _lives--; } @@ -3713,7 +3713,7 @@ namespace Jazz2::Actors _controllable = true; }); - float invulnerableTime = (_levelHandler->Difficulty() == GameDifficulty::Multiplayer ? 80.0f : 180.0f); + float invulnerableTime = (!_levelHandler->IsLocalSession() ? 80.0f : 180.0f); SetInvulnerability(invulnerableTime, InvulnerableType::Blinking); PlayPlayerSfx("Hurt"_s); _levelHandler->PlayerExecuteRumble(_playerIndex, "Hurt"_s); diff --git a/Sources/Jazz2/Actors/Solid/GenericContainer.h b/Sources/Jazz2/Actors/Solid/GenericContainer.h index f09ba107..57bacee4 100644 --- a/Sources/Jazz2/Actors/Solid/GenericContainer.h +++ b/Sources/Jazz2/Actors/Solid/GenericContainer.h @@ -5,6 +5,7 @@ namespace Jazz2::Actors::Solid { + /** @brief Base class of an item container */ class GenericContainer : public SolidObjectBase { DEATH_RUNTIME_OBJECT(SolidObjectBase); diff --git a/Sources/Jazz2/AnimState.h b/Sources/Jazz2/AnimState.h index 2b68d388..67c01dc1 100644 --- a/Sources/Jazz2/AnimState.h +++ b/Sources/Jazz2/AnimState.h @@ -4,6 +4,7 @@ namespace Jazz2 { + /** @brief Well-known animation state */ enum class AnimState { // Bits 0, 1: Horizontal speed (none, low, med, high) @@ -94,5 +95,5 @@ namespace Jazz2 Default = 0 }; - DEFINE_ENUM_OPERATORS(AnimState); + DEATH_ENUM_FLAGS(AnimState); } \ No newline at end of file diff --git a/Sources/Jazz2/Compatibility/JJ2Version.h b/Sources/Jazz2/Compatibility/JJ2Version.h index b1f0ec1f..0e3cfe7a 100644 --- a/Sources/Jazz2/Compatibility/JJ2Version.h +++ b/Sources/Jazz2/Compatibility/JJ2Version.h @@ -19,5 +19,5 @@ namespace Jazz2::Compatibility All = 0xffff }; - DEFINE_ENUM_OPERATORS(JJ2Version); + DEATH_ENUM_FLAGS(JJ2Version); } \ No newline at end of file diff --git a/Sources/Jazz2/Direction.h b/Sources/Jazz2/Direction.h index 839e26ce..cfd7b7e6 100644 --- a/Sources/Jazz2/Direction.h +++ b/Sources/Jazz2/Direction.h @@ -17,5 +17,5 @@ namespace Jazz2 Any = Up | Down | Left | Right }; - DEFINE_ENUM_OPERATORS(Direction); + DEATH_ENUM_FLAGS(Direction); } \ No newline at end of file diff --git a/Sources/Jazz2/ExitType.h b/Sources/Jazz2/ExitType.h index 668a689a..f27660b6 100644 --- a/Sources/Jazz2/ExitType.h +++ b/Sources/Jazz2/ExitType.h @@ -20,5 +20,5 @@ namespace Jazz2 FastTransition = 0x80 }; - DEFINE_ENUM_OPERATORS(ExitType); + DEATH_ENUM_FLAGS(ExitType); } \ No newline at end of file diff --git a/Sources/Jazz2/GameDifficulty.h b/Sources/Jazz2/GameDifficulty.h index 3f786feb..043a957a 100644 --- a/Sources/Jazz2/GameDifficulty.h +++ b/Sources/Jazz2/GameDifficulty.h @@ -11,8 +11,6 @@ namespace Jazz2 Easy, Normal, - Hard, - - Multiplayer + Hard }; } \ No newline at end of file diff --git a/Sources/Jazz2/ILevelHandler.h b/Sources/Jazz2/ILevelHandler.h index 281742fa..56896d92 100644 --- a/Sources/Jazz2/ILevelHandler.h +++ b/Sources/Jazz2/ILevelHandler.h @@ -45,14 +45,23 @@ namespace Jazz2 static constexpr std::int32_t SpritePlaneZ = MainPlaneZ + 10; static constexpr std::int32_t PlayerZ = MainPlaneZ + 20; + /** @brief Initializes the level handler from @ref LevelInitialization */ virtual bool Initialize(const LevelInitialization& levelInit) = 0; + /** @brief Initializes the level handler from resumable state */ virtual bool Initialize(Stream& src, std::uint16_t version) = 0; + /** @brief Returns event spawner for the level */ virtual Events::EventSpawner* EventSpawner() = 0; + /** @brief Returns event map for the level */ virtual Events::EventMap* EventMap() = 0; + /** @brief Returns tile map for the level */ virtual Tiles::TileMap* TileMap() = 0; + /** @brief Return current difficulty */ virtual GameDifficulty Difficulty() const = 0; + /** @brief Return `true` if the level handler is on a local session */ + virtual bool IsLocalSession() const = 0; + /** @brief Return `true` if the level handler is pausable */ virtual bool IsPausable() const = 0; virtual bool IsReforged() const = 0; virtual bool CanPlayersCollide() const = 0; diff --git a/Sources/Jazz2/IResumable.h b/Sources/Jazz2/IResumable.h index afac94c1..099f9fc2 100644 --- a/Sources/Jazz2/IResumable.h +++ b/Sources/Jazz2/IResumable.h @@ -14,6 +14,7 @@ namespace Jazz2 public: IResumable() {} + /** @brief Serializes object state to a stream */ virtual bool SerializeResumableToStream(Stream& dest) = 0; }; } \ No newline at end of file diff --git a/Sources/Jazz2/IRootController.h b/Sources/Jazz2/IRootController.h index 4f98925a..192492e3 100644 --- a/Sources/Jazz2/IRootController.h +++ b/Sources/Jazz2/IRootController.h @@ -13,6 +13,7 @@ namespace Jazz2 class IRootController { public: + /** @brief State flags of root controller, supports a bitwise combination of its member values */ enum class Flags { None = 0x00, @@ -26,7 +27,7 @@ namespace Jazz2 #endif }; - DEFINE_PRIVATE_ENUM_OPERATORS(Flags); + DEATH_PRIVATE_ENUM_FLAGS(Flags); IRootController() { } virtual ~IRootController() { } @@ -34,24 +35,37 @@ namespace Jazz2 IRootController(const IRootController&) = delete; IRootController& operator=(const IRootController&) = delete; + /** @brief Invokes the specified callback asynchronously, usually at the end of current frame */ virtual void InvokeAsync(Function&& callback, const char* sourceFunc = nullptr) = 0; + /** @brief Sets current state handler to main menu */ virtual void GoToMainMenu(bool afterIntro) = 0; + /** @brief Sets current state handler to level described by @ref LevelInitialization */ virtual void ChangeLevel(LevelInitialization&& levelInit) = 0; + /** @brief Returns `true` if any resumable state exists */ virtual bool HasResumableState() const = 0; + /** @brief Resumes saved resumable state */ virtual void ResumeSavedState() = 0; + /** @brief Saves current state if it's resumable */ virtual bool SaveCurrentStateIfAny() = 0; #if defined(WITH_MULTIPLAYER) + /** @brief Sets current state handler to remove multiplayer session */ virtual bool ConnectToServer(StringView address, std::uint16_t port) = 0; + /** @brief Creates a multiplayer server */ virtual bool CreateServer(LevelInitialization&& levelInit, std::uint16_t port) = 0; + /** @brief Returns name of the server */ virtual StringView GetServerName() const = 0; + /** @brief Sets name of the server */ virtual void SetServerName(StringView value) = 0; #endif + /** @brief Returns current state flags */ virtual Flags GetFlags() const = 0; + /** @brief Returns version of the latest update */ virtual StringView GetNewestVersion() const = 0; + /** @brief Recreates level cache from `Source` directory */ virtual void RefreshCacheLevels() = 0; }; } \ No newline at end of file diff --git a/Sources/Jazz2/LevelFlags.h b/Sources/Jazz2/LevelFlags.h index a6afb6be..f6bb116b 100644 --- a/Sources/Jazz2/LevelFlags.h +++ b/Sources/Jazz2/LevelFlags.h @@ -19,5 +19,5 @@ namespace Jazz2 HasMultiplayerSpawnPoints = 0x100 }; - DEFINE_ENUM_OPERATORS(LevelFlags); + DEATH_ENUM_FLAGS(LevelFlags); } \ No newline at end of file diff --git a/Sources/Jazz2/LevelHandler.cpp b/Sources/Jazz2/LevelHandler.cpp index 05271276..0884ca5a 100644 --- a/Sources/Jazz2/LevelHandler.cpp +++ b/Sources/Jazz2/LevelHandler.cpp @@ -285,6 +285,11 @@ namespace Jazz2 return _difficulty; } + bool LevelHandler::IsLocalSession() const + { + return true; + } + bool LevelHandler::IsPausable() const { return true; @@ -1158,7 +1163,7 @@ namespace Jazz2 player->SetCheckpoint(pos, ambientLight); } - if (_difficulty != GameDifficulty::Multiplayer) { + if (IsLocalSession()) { _eventMap->CreateCheckpointForRollback(); } } @@ -1170,7 +1175,7 @@ namespace Jazz2 WarpCameraToTarget(player); - if (_difficulty != GameDifficulty::Multiplayer) { + if (IsLocalSession()) { for (auto& actor : _actors) { // Despawn all actors that were created after the last checkpoint if (actor->_spawnFrames > _checkpointFrames && !actor->GetState(Actors::ActorState::PreserveOnRollback)) { @@ -2200,7 +2205,7 @@ namespace Jazz2 bool LevelHandler::CheatKill() { - if (PreferencesCache::AllowCheats && _difficulty != GameDifficulty::Multiplayer && !_players.empty()) { + if (PreferencesCache::AllowCheats && IsLocalSession() && !_players.empty()) { _cheatsUsed = true; for (auto* player : _players) { player->TakeDamage(INT32_MAX); @@ -2213,7 +2218,7 @@ namespace Jazz2 bool LevelHandler::CheatGod() { - if (PreferencesCache::AllowCheats && _difficulty != GameDifficulty::Multiplayer && !_players.empty()) { + if (PreferencesCache::AllowCheats && IsLocalSession() && !_players.empty()) { _cheatsUsed = true; for (auto* player : _players) { player->SetInvulnerability(36000.0f, Actors::Player::InvulnerableType::Shielded); @@ -2226,7 +2231,7 @@ namespace Jazz2 bool LevelHandler::CheatNext() { - if (PreferencesCache::AllowCheats && _difficulty != GameDifficulty::Multiplayer && !_players.empty()) { + if (PreferencesCache::AllowCheats && IsLocalSession() && !_players.empty()) { _cheatsUsed = true; BeginLevelChange(nullptr, ExitType::Warp | ExitType::FastTransition); } else { @@ -2237,7 +2242,7 @@ namespace Jazz2 bool LevelHandler::CheatGuns() { - if (PreferencesCache::AllowCheats && _difficulty != GameDifficulty::Multiplayer && !_players.empty()) { + if (PreferencesCache::AllowCheats && IsLocalSession() && !_players.empty()) { _cheatsUsed = true; for (auto* player : _players) { for (std::int32_t i = 0; i < (std::int32_t)WeaponType::Count; i++) { @@ -2252,7 +2257,7 @@ namespace Jazz2 bool LevelHandler::CheatRush() { - if (PreferencesCache::AllowCheats && _difficulty != GameDifficulty::Multiplayer && !_players.empty()) { + if (PreferencesCache::AllowCheats && IsLocalSession() && !_players.empty()) { _cheatsUsed = true; for (auto* player : _players) { player->ActivateSugarRush(1300.0f); @@ -2265,7 +2270,7 @@ namespace Jazz2 bool LevelHandler::CheatGems() { - if (PreferencesCache::AllowCheats && _difficulty != GameDifficulty::Multiplayer && !_players.empty()) { + if (PreferencesCache::AllowCheats && IsLocalSession() && !_players.empty()) { _cheatsUsed = true; for (auto* player : _players) { player->AddGems(0, 5); @@ -2278,7 +2283,7 @@ namespace Jazz2 bool LevelHandler::CheatBird() { - if (PreferencesCache::AllowCheats && _difficulty != GameDifficulty::Multiplayer && !_players.empty()) { + if (PreferencesCache::AllowCheats && IsLocalSession() && !_players.empty()) { _cheatsUsed = true; for (auto* player : _players) { player->SpawnBird(0, player->GetPos()); @@ -2291,7 +2296,7 @@ namespace Jazz2 bool LevelHandler::CheatPower() { - if (PreferencesCache::AllowCheats && _difficulty != GameDifficulty::Multiplayer && !_players.empty()) { + if (PreferencesCache::AllowCheats && IsLocalSession() && !_players.empty()) { _cheatsUsed = true; for (auto* player : _players) { for (std::int32_t i = 0; i < (std::int32_t)WeaponType::Count; i++) { @@ -2306,7 +2311,7 @@ namespace Jazz2 bool LevelHandler::CheatCoins() { - if (PreferencesCache::AllowCheats && _difficulty != GameDifficulty::Multiplayer && !_players.empty()) { + if (PreferencesCache::AllowCheats && IsLocalSession() && !_players.empty()) { _cheatsUsed = true; // Coins are synchronized automatically _players[0]->AddCoins(5); @@ -2318,7 +2323,7 @@ namespace Jazz2 bool LevelHandler::CheatMorph() { - if (PreferencesCache::AllowCheats && _difficulty != GameDifficulty::Multiplayer && !_players.empty()) { + if (PreferencesCache::AllowCheats && IsLocalSession() && !_players.empty()) { _cheatsUsed = true; PlayerType newType; @@ -2339,7 +2344,7 @@ namespace Jazz2 bool LevelHandler::CheatShield() { - if (PreferencesCache::AllowCheats && _difficulty != GameDifficulty::Multiplayer && !_players.empty()) { + if (PreferencesCache::AllowCheats && IsLocalSession() && !_players.empty()) { _cheatsUsed = true; for (auto* player : _players) { ShieldType shieldType = (ShieldType)(((std::int32_t)player->GetActiveShield() + 1) % (std::int32_t)ShieldType::Count); diff --git a/Sources/Jazz2/LevelHandler.h b/Sources/Jazz2/LevelHandler.h index 670fab4e..0223bbb4 100644 --- a/Sources/Jazz2/LevelHandler.h +++ b/Sources/Jazz2/LevelHandler.h @@ -93,6 +93,7 @@ namespace Jazz2 Tiles::TileMap* TileMap() override; GameDifficulty Difficulty() const override; + bool IsLocalSession() const override; bool IsPausable() const override; bool IsReforged() const override; bool CanPlayersCollide() const override; diff --git a/Sources/Jazz2/LevelInitialization.h b/Sources/Jazz2/LevelInitialization.h index 392e2c3f..6f49839d 100644 --- a/Sources/Jazz2/LevelInitialization.h +++ b/Sources/Jazz2/LevelInitialization.h @@ -40,6 +40,7 @@ namespace Jazz2 String EpisodeName; String LastEpisodeName; + bool IsLocalSession; GameDifficulty Difficulty; bool IsReforged, CheatsUsed; ExitType LastExitType; @@ -48,12 +49,12 @@ namespace Jazz2 PlayerCarryOver PlayerCarryOvers[MaxPlayerCount]; LevelInitialization() - : ElapsedMilliseconds(0), PlayerCarryOvers{} + : IsLocalSession(true), ElapsedMilliseconds(0), PlayerCarryOvers{} { } LevelInitialization(StringView episode, StringView level, GameDifficulty difficulty, bool isReforged) - : ElapsedMilliseconds(0), PlayerCarryOvers{} + : IsLocalSession(true), ElapsedMilliseconds(0), PlayerCarryOvers{} { LevelName = level; EpisodeName = episode; @@ -69,7 +70,7 @@ namespace Jazz2 } LevelInitialization(StringView episode, StringView level, GameDifficulty difficulty, bool isReforged, bool cheatsUsed, PlayerType playerType) - : ElapsedMilliseconds(0), PlayerCarryOvers{} + : IsLocalSession(true), ElapsedMilliseconds(0), PlayerCarryOvers{} { LevelName = level; EpisodeName = episode; @@ -88,7 +89,7 @@ namespace Jazz2 } LevelInitialization(StringView episode, StringView level, GameDifficulty difficulty, bool isReforged, bool cheatsUsed, ArrayView playerTypes) - : ElapsedMilliseconds(0), PlayerCarryOvers{} + : IsLocalSession(true), ElapsedMilliseconds(0), PlayerCarryOvers{} { LevelName = level; EpisodeName = episode; @@ -113,6 +114,7 @@ namespace Jazz2 { LevelName = copy.LevelName; EpisodeName = copy.EpisodeName; + IsLocalSession = copy.IsLocalSession; Difficulty = copy.Difficulty; IsReforged = copy.IsReforged; CheatsUsed = copy.CheatsUsed; @@ -127,6 +129,7 @@ namespace Jazz2 { LevelName = std::move(move.LevelName); EpisodeName = std::move(move.EpisodeName); + IsLocalSession = move.IsLocalSession; Difficulty = move.Difficulty; IsReforged = move.IsReforged; CheatsUsed = move.CheatsUsed; diff --git a/Sources/Jazz2/Multiplayer/MultiLevelHandler.cpp b/Sources/Jazz2/Multiplayer/MultiLevelHandler.cpp index 154b7378..50de7417 100644 --- a/Sources/Jazz2/Multiplayer/MultiLevelHandler.cpp +++ b/Sources/Jazz2/Multiplayer/MultiLevelHandler.cpp @@ -74,6 +74,8 @@ namespace Jazz2::Multiplayer bool MultiLevelHandler::Initialize(const LevelInitialization& levelInit) { + DEATH_DEBUG_ASSERT(!levelInit.IsLocalSession); + _suppressRemoting = true; bool initialized = LevelHandler::Initialize(levelInit); _suppressRemoting = false; @@ -108,6 +110,16 @@ namespace Jazz2::Multiplayer return true; } + bool MultiLevelHandler::IsLocalSession() const + { + return false; + } + + bool MultiLevelHandler::IsPausable() const + { + return false; + } + float MultiLevelHandler::GetDefaultAmbientLight() const { // TODO: Remove this override diff --git a/Sources/Jazz2/Multiplayer/MultiLevelHandler.h b/Sources/Jazz2/Multiplayer/MultiLevelHandler.h index 2c95e3b2..b7632436 100644 --- a/Sources/Jazz2/Multiplayer/MultiLevelHandler.h +++ b/Sources/Jazz2/Multiplayer/MultiLevelHandler.h @@ -31,9 +31,8 @@ namespace Jazz2::Multiplayer bool Initialize(const LevelInitialization& levelInit) override; - bool IsPausable() const override { - return false; - } + bool IsLocalSession() const override; + bool IsPausable() const override; float GetDefaultAmbientLight() const override; void SetAmbientLight(Actors::Player* player, float value) override; @@ -142,7 +141,7 @@ namespace Jazz2::Multiplayer JustWarped = 0x100 }; - DEFINE_PRIVATE_ENUM_OPERATORS(PlayerFlags); + DEATH_PRIVATE_ENUM_FLAGS(PlayerFlags); #ifndef DOXYGEN_GENERATING_OUTPUT // Doxygen 1.12.0 outputs also private structs/unions even if it shouldn't diff --git a/Sources/Jazz2/PlayerActions.h b/Sources/Jazz2/PlayerActions.h index 821e9fb4..dea2683a 100644 --- a/Sources/Jazz2/PlayerActions.h +++ b/Sources/Jazz2/PlayerActions.h @@ -2,7 +2,7 @@ namespace Jazz2 { - /** @brief Player actions */ + /** @brief Player action */ enum class PlayerActions { Left, diff --git a/Sources/Jazz2/PreferencesCache.h b/Sources/Jazz2/PreferencesCache.h index 541353c8..2587fae1 100644 --- a/Sources/Jazz2/PreferencesCache.h +++ b/Sources/Jazz2/PreferencesCache.h @@ -23,7 +23,7 @@ namespace Jazz2 UseAntialiasing = 0x80 }; - DEFINE_ENUM_OPERATORS(RescaleMode); + DEATH_ENUM_FLAGS(RescaleMode); /** @brief Weapon wheel style */ enum class WeaponWheelStyle : std::uint8_t { @@ -40,12 +40,14 @@ namespace Jazz2 Switch }; + /** @brief Episode completion overwrite mode */ enum class EpisodeEndOverwriteMode : std::uint8_t { Always, NoCheatsOnly, HigherScoreOnly }; + /** @brief Unlockable episodes, mainly used if compiled with `SHAREWARE_DEMO_ONLY` */ enum class UnlockableEpisodes : std::uint32_t { None = 0x00, @@ -57,8 +59,9 @@ namespace Jazz2 TheSecretFiles = 0x20, }; - DEFINE_ENUM_OPERATORS(UnlockableEpisodes); + DEATH_ENUM_FLAGS(UnlockableEpisodes); + /** @brief Episode continuation flags, supports a bitwise combination of its member values */ enum class EpisodeContinuationFlags : std::uint8_t { None = 0x00, @@ -66,7 +69,7 @@ namespace Jazz2 CheatsUsed = 0x02 }; - DEFINE_ENUM_OPERATORS(EpisodeContinuationFlags); + DEATH_ENUM_FLAGS(EpisodeContinuationFlags); # pragma pack(push, 1) @@ -201,7 +204,7 @@ namespace Jazz2 PlayStationExtendedSupport = 0x4000000, }; - DEFINE_PRIVATE_ENUM_OPERATORS(BoolOptions); + DEATH_PRIVATE_ENUM_FLAGS(BoolOptions); static constexpr std::uint8_t FileVersion = 8; diff --git a/Sources/Jazz2/Resources.h b/Sources/Jazz2/Resources.h index 7d526a4b..b1133fa5 100644 --- a/Sources/Jazz2/Resources.h +++ b/Sources/Jazz2/Resources.h @@ -20,6 +20,7 @@ using namespace nCine; namespace Jazz2 { + /** @brief Flags for @ref GenericGraphicResource, supports a bitwise combination of its member values */ enum class GenericGraphicResourceFlags { None = 0x00, @@ -27,7 +28,7 @@ namespace Jazz2 Referenced = 0x01 }; - DEFINE_ENUM_OPERATORS(GenericGraphicResourceFlags); + DEATH_ENUM_FLAGS(GenericGraphicResourceFlags); /** @brief Shared graphic resource */ struct GenericGraphicResource @@ -62,6 +63,7 @@ namespace Jazz2 bool operator<(const GraphicResource& p) const noexcept; }; + /** @brief Flags for @ref GenericSoundResource, supports a bitwise combination of its member values */ enum class GenericSoundResourceFlags { None = 0x00, @@ -69,7 +71,7 @@ namespace Jazz2 Referenced = 0x01 }; - DEFINE_ENUM_OPERATORS(GenericSoundResourceFlags); + DEATH_ENUM_FLAGS(GenericSoundResourceFlags); /** @brief Shared sound resource */ struct GenericSoundResource @@ -88,6 +90,7 @@ namespace Jazz2 SoundResource() noexcept; }; + /** @brief Flags for @ref Metadata, supports a bitwise combination of its member values */ enum class MetadataFlags { None = 0x00, @@ -95,7 +98,7 @@ namespace Jazz2 AsyncFinalizingRequired = 0x02 }; - DEFINE_ENUM_OPERATORS(MetadataFlags); + DEATH_ENUM_FLAGS(MetadataFlags); /** @brief Contains assets for specific object type */ struct Metadata diff --git a/Sources/Jazz2/Tiles/TileDestructType.h b/Sources/Jazz2/Tiles/TileDestructType.h index cd21773a..c8aafd69 100644 --- a/Sources/Jazz2/Tiles/TileDestructType.h +++ b/Sources/Jazz2/Tiles/TileDestructType.h @@ -19,5 +19,5 @@ namespace Jazz2::Tiles VerticalMove = 0x40, }; - DEFINE_ENUM_OPERATORS(TileDestructType); + DEATH_ENUM_FLAGS(TileDestructType); } \ No newline at end of file diff --git a/Sources/Jazz2/Tiles/TileMap.h b/Sources/Jazz2/Tiles/TileMap.h index 1ae7f867..5f91fb64 100644 --- a/Sources/Jazz2/Tiles/TileMap.h +++ b/Sources/Jazz2/Tiles/TileMap.h @@ -74,7 +74,7 @@ namespace Jazz2::Tiles OneWay = 0x10 }; - DEFINE_ENUM_OPERATORS(LayerTileFlags); + DEATH_ENUM_FLAGS(LayerTileFlags); /** @brief Represents a single tile in a tile map layer */ struct LayerTile { @@ -135,7 +135,7 @@ namespace Jazz2::Tiles AdditiveBlending = 0x04 }; - DEFINE_PRIVATE_ENUM_OPERATORS(DebrisFlags); + DEATH_PRIVATE_ENUM_FLAGS(DebrisFlags); /** @brief Describes a visual debris (particle effect) */ struct DestructibleDebris { diff --git a/Sources/Jazz2/UI/Alignment.h b/Sources/Jazz2/UI/Alignment.h index d98fa034..f02d285c 100644 --- a/Sources/Jazz2/UI/Alignment.h +++ b/Sources/Jazz2/UI/Alignment.h @@ -23,5 +23,5 @@ namespace Jazz2::UI VerticalMask = Top | Center | Bottom }; - DEFINE_ENUM_OPERATORS(Alignment); + DEATH_ENUM_FLAGS(Alignment); } \ No newline at end of file diff --git a/Sources/Jazz2/UI/ControlScheme.h b/Sources/Jazz2/UI/ControlScheme.h index 96deb19a..16f3c3a3 100644 --- a/Sources/Jazz2/UI/ControlScheme.h +++ b/Sources/Jazz2/UI/ControlScheme.h @@ -27,7 +27,7 @@ namespace Jazz2::UI AllowAll = AllowKeyboard | AllowGamepads }; - DEFINE_ENUM_OPERATORS(NavigationFlags); + DEATH_ENUM_FLAGS(NavigationFlags); /** @brief Mapping target */ struct MappingTarget diff --git a/Sources/Jazz2/UI/FormattedTextBlock.h b/Sources/Jazz2/UI/FormattedTextBlock.h index 844bc6d7..8f26438f 100644 --- a/Sources/Jazz2/UI/FormattedTextBlock.h +++ b/Sources/Jazz2/UI/FormattedTextBlock.h @@ -147,7 +147,7 @@ namespace Jazz2::UI Ellipsized = 0x10 }; - DEFINE_PRIVATE_ENUM_OPERATORS(FormattedTextBlockFlags); + DEATH_PRIVATE_ENUM_FLAGS(FormattedTextBlockFlags); SmallVector _parts; SmallVector _background; diff --git a/Sources/Jazz2/UI/Menu/CreateServerOptionsSection.cpp b/Sources/Jazz2/UI/Menu/CreateServerOptionsSection.cpp index ccda2aa6..c87a5118 100644 --- a/Sources/Jazz2/UI/Menu/CreateServerOptionsSection.cpp +++ b/Sources/Jazz2/UI/Menu/CreateServerOptionsSection.cpp @@ -338,8 +338,9 @@ namespace Jazz2::UI::Menu { // TODO: _gameMode is ignored PlayerType players[] = { (PlayerType)((int32_t)PlayerType::Jazz + _selectedPlayerType) }; - LevelInitialization levelInit(_episodeName, StringView(_levelName), GameDifficulty::Multiplayer, + LevelInitialization levelInit(_episodeName, StringView(_levelName), GameDifficulty::Normal, PreferencesCache::EnableReforgedGameplay, false, players); + levelInit.IsLocalSession = false; if (!_previousEpisodeName.empty()) { auto previousEpisodeEnd = PreferencesCache::GetEpisodeEnd(_previousEpisodeName); diff --git a/Sources/Jazz2/UI/Menu/EpisodeSelectSection.h b/Sources/Jazz2/UI/Menu/EpisodeSelectSection.h index 6664eda5..41691929 100644 --- a/Sources/Jazz2/UI/Menu/EpisodeSelectSection.h +++ b/Sources/Jazz2/UI/Menu/EpisodeSelectSection.h @@ -14,7 +14,7 @@ namespace Jazz2::UI::Menu CheatsUsed = 0x10, }; - DEFINE_ENUM_OPERATORS(EpisodeDataFlags); + DEATH_ENUM_FLAGS(EpisodeDataFlags); struct EpisodeData { Episode Description; diff --git a/Sources/Jazz2/UI/Menu/HighscoresSection.h b/Sources/Jazz2/UI/Menu/HighscoresSection.h index 94466268..f44514e8 100644 --- a/Sources/Jazz2/UI/Menu/HighscoresSection.h +++ b/Sources/Jazz2/UI/Menu/HighscoresSection.h @@ -12,7 +12,7 @@ namespace Jazz2::UI::Menu CheatsUsed = 0x04 }; - DEFINE_ENUM_OPERATORS(HighscoreFlags); + DEATH_ENUM_FLAGS(HighscoreFlags); struct HighscoreItem { String PlayerName; diff --git a/Sources/Jazz2/UI/Menu/IMenuContainer.h b/Sources/Jazz2/UI/Menu/IMenuContainer.h index 3a7c282d..76195557 100644 --- a/Sources/Jazz2/UI/Menu/IMenuContainer.h +++ b/Sources/Jazz2/UI/Menu/IMenuContainer.h @@ -22,7 +22,7 @@ namespace Jazz2::UI::Menu MainMenu = 0x20 }; - DEFINE_ENUM_OPERATORS(ChangedPreferencesType); + DEATH_ENUM_FLAGS(ChangedPreferencesType); /** @brief Base interface of a menu container */ class IMenuContainer diff --git a/Sources/Jazz2/WarpFlags.h b/Sources/Jazz2/WarpFlags.h index 341cce4e..e1f3a10c 100644 --- a/Sources/Jazz2/WarpFlags.h +++ b/Sources/Jazz2/WarpFlags.h @@ -16,5 +16,5 @@ namespace Jazz2 IncrementLaps = 0x10 }; - DEFINE_ENUM_OPERATORS(WarpFlags); + DEATH_ENUM_FLAGS(WarpFlags); } \ No newline at end of file diff --git a/Sources/Jazz2/WeatherType.h b/Sources/Jazz2/WeatherType.h index 9129274c..b8e73e6a 100644 --- a/Sources/Jazz2/WeatherType.h +++ b/Sources/Jazz2/WeatherType.h @@ -17,5 +17,5 @@ namespace Jazz2 OutdoorsOnly = 0x80 }; - DEFINE_ENUM_OPERATORS(WeatherType); + DEATH_ENUM_FLAGS(WeatherType); } \ No newline at end of file diff --git a/Sources/Main.cpp b/Sources/Main.cpp index 5b9ef5e7..5d63047b 100644 --- a/Sources/Main.cpp +++ b/Sources/Main.cpp @@ -648,7 +648,7 @@ bool GameEventHandler::SaveCurrentStateIfAny() ZoneScopedNC("GameEventHandler::SaveCurrentStateIfAny", 0x888888); if (auto* levelHandler = dynamic_cast(_currentHandler.get())) { - if (levelHandler->Difficulty() != GameDifficulty::Multiplayer) { + if (levelHandler->IsLocalSession()) { auto configDir = PreferencesCache::GetDirectory(); auto s = fs::Open(fs::CombinePath(configDir, StateFileName), FileAccess::Write); if (*s) { @@ -858,7 +858,9 @@ void GameEventHandler::OnPacketReceived(const Peer& peer, std::uint8_t channelId InvokeAsync([this, flags, gameMode, episodeName = std::move(episodeName), levelName = std::move(levelName)]() { bool isReforged = (flags & 0x01) != 0; - LevelInitialization levelInit(episodeName, levelName, GameDifficulty::Multiplayer, isReforged); + LevelInitialization levelInit(episodeName, levelName, GameDifficulty::Normal, isReforged); + levelInit.IsLocalSession = false; + auto levelHandler = std::make_unique(this, _networkManager.get()); levelHandler->SetGameMode(gameMode); levelHandler->Initialize(levelInit); @@ -1548,7 +1550,7 @@ void GameEventHandler::CheckUpdates() bool GameEventHandler::SetLevelHandler(const LevelInitialization& levelInit) { #if defined(WITH_MULTIPLAYER) - if (levelInit.Difficulty == GameDifficulty::Multiplayer) { + if (!levelInit.IsLocalSession) { auto levelHandler = std::make_unique(this, _networkManager.get()); if (!levelHandler->Initialize(levelInit)) { return false; @@ -1565,7 +1567,7 @@ bool GameEventHandler::SetLevelHandler(const LevelInitialization& levelInit) SetStateHandler(std::move(levelHandler)); #if !defined(SHAREWARE_DEMO_ONLY) - if (levelInit.Difficulty != GameDifficulty::Multiplayer) { + if (levelInit.IsLocalSession) { RemoveResumableStateIfAny(); } #endif @@ -1579,7 +1581,7 @@ void GameEventHandler::HandleEndOfGame(const LevelInitialization& levelInit, boo std::size_t playerCount = levelInit.GetPlayerCount(&firstPlayer); auto mainMenu = std::make_unique(this, false); - if (playerCount == 1 && levelInit.Difficulty != GameDifficulty::Multiplayer) { + if (playerCount == 1 && levelInit.IsLocalSession) { std::int32_t seriesIndex = Menu::HighscoresSection::TryGetSeriesIndex(levelInit.LastEpisodeName, playerDied); if (seriesIndex >= 0) { mainMenu->SwitchToSection(seriesIndex, levelInit.Difficulty, @@ -1648,7 +1650,7 @@ void GameEventHandler::SaveEpisodeEnd(const LevelInitialization& levelInit) void GameEventHandler::SaveEpisodeContinue(const LevelInitialization& levelInit) { if (levelInit.EpisodeName.empty() || levelInit.LevelName.empty() || - levelInit.EpisodeName == "unknown"_s || levelInit.Difficulty == GameDifficulty::Multiplayer || + !levelInit.IsLocalSession || levelInit.EpisodeName == "unknown"_s || (levelInit.EpisodeName == "prince"_s && levelInit.LevelName == "trainer"_s)) { return; } diff --git a/Sources/Shared/Common.h b/Sources/Shared/Common.h index d34fe228..c21b5c61 100644 --- a/Sources/Shared/Common.h +++ b/Sources/Shared/Common.h @@ -6,7 +6,7 @@ #include #include -#if !defined(countof) +#if !defined(countof) && !defined(DOXYGEN_GENERATING_OUTPUT) # if defined(__cplusplus) namespace Death { namespace Implementation { template char(*__ArrayCountOfHelper(T(&)[N]))[N]; @@ -17,7 +17,6 @@ # endif #endif -#if defined(__cplusplus) namespace Death { namespace Implementation { // Used as an approximation of std::underlying_type template struct __EnumTypeForSize; @@ -28,32 +27,36 @@ namespace Death { namespace Implementation { template struct __EnumSizedInteger { using Type = typename __EnumTypeForSize::Type; }; }} -# define DEFINE_ENUM_OPERATORS(type) \ - inline DEATH_CONSTEXPR14 type operator|(type a, type b) { return type(((Death::Implementation::__EnumSizedInteger::Type)a) | ((Death::Implementation::__EnumSizedInteger::Type)b)); } \ - inline type& operator|=(type& a, type b) { return (type&)(((Death::Implementation::__EnumSizedInteger::Type&)a) |= ((Death::Implementation::__EnumSizedInteger::Type)b)); } \ - inline DEATH_CONSTEXPR14 type operator&(type a, type b) { return type(((Death::Implementation::__EnumSizedInteger::Type)a) & ((Death::Implementation::__EnumSizedInteger::Type)b)); } \ - inline type& operator&=(type& a, type b) { return (type&)(((Death::Implementation::__EnumSizedInteger::Type&)a) &= ((Death::Implementation::__EnumSizedInteger::Type)b)); } \ - inline DEATH_CONSTEXPR14 type operator~(type a) { return type(~((Death::Implementation::__EnumSizedInteger::Type)a)); } \ - inline DEATH_CONSTEXPR14 type operator^(type a, type b) { return type(((Death::Implementation::__EnumSizedInteger::Type)a) ^ ((Death::Implementation::__EnumSizedInteger::Type)b)); } \ - inline type& operator^=(type& a, type b) { return (type&)(((Death::Implementation::__EnumSizedInteger::Type&)a) ^= ((Death::Implementation::__EnumSizedInteger::Type)b)); } +/** @brief Mark an enum as a set of flags */ +#define DEATH_ENUM_FLAGS(type) \ + inline DEATH_CONSTEXPR14 type operator|(type a, type b) { return type(((Death::Implementation::__EnumSizedInteger::Type)a) | ((Death::Implementation::__EnumSizedInteger::Type)b)); } \ + inline type& operator|=(type& a, type b) { return (type&)(((Death::Implementation::__EnumSizedInteger::Type&)a) |= ((Death::Implementation::__EnumSizedInteger::Type)b)); } \ + inline DEATH_CONSTEXPR14 type operator&(type a, type b) { return type(((Death::Implementation::__EnumSizedInteger::Type)a) & ((Death::Implementation::__EnumSizedInteger::Type)b)); } \ + inline type& operator&=(type& a, type b) { return (type&)(((Death::Implementation::__EnumSizedInteger::Type&)a) &= ((Death::Implementation::__EnumSizedInteger::Type)b)); } \ + inline DEATH_CONSTEXPR14 type operator~(type a) { return type(~((Death::Implementation::__EnumSizedInteger::Type)a)); } \ + inline DEATH_CONSTEXPR14 type operator^(type a, type b) { return type(((Death::Implementation::__EnumSizedInteger::Type)a) ^ ((Death::Implementation::__EnumSizedInteger::Type)b)); } \ + inline type& operator^=(type& a, type b) { return (type&)(((Death::Implementation::__EnumSizedInteger::Type&)a) ^= ((Death::Implementation::__EnumSizedInteger::Type)b)); } -# define DEFINE_PRIVATE_ENUM_OPERATORS(type) \ - friend inline DEATH_CONSTEXPR14 type operator|(type a, type b) { return type(((Death::Implementation::__EnumSizedInteger::Type)a) | ((Death::Implementation::__EnumSizedInteger::Type)b)); } \ - friend inline type& operator|=(type& a, type b) { return (type&)(((Death::Implementation::__EnumSizedInteger::Type&)a) |= ((Death::Implementation::__EnumSizedInteger::Type)b)); } \ - friend inline DEATH_CONSTEXPR14 type operator&(type a, type b) { return type(((Death::Implementation::__EnumSizedInteger::Type)a) & ((Death::Implementation::__EnumSizedInteger::Type)b)); } \ - friend inline type& operator&=(type& a, type b) { return (type&)(((Death::Implementation::__EnumSizedInteger::Type&)a) &= ((Death::Implementation::__EnumSizedInteger::Type)b)); } \ - friend inline DEATH_CONSTEXPR14 type operator~(type a) { return type(~((Death::Implementation::__EnumSizedInteger::Type)a)); } \ - friend inline DEATH_CONSTEXPR14 type operator^(type a, type b) { return type(((Death::Implementation::__EnumSizedInteger::Type)a) ^ ((Death::Implementation::__EnumSizedInteger::Type)b)); } \ - friend inline type& operator^=(type& a, type b) { return (type&)(((Death::Implementation::__EnumSizedInteger::Type&)a) ^= ((Death::Implementation::__EnumSizedInteger::Type)b)); } -#else -# define DEFINE_ENUM_OPERATORS(type) -# define DEFINE_PRIVATE_ENUM_OPERATORS(type) -#endif +/** @brief Mark a private enum as a set of flags */ +#define DEATH_PRIVATE_ENUM_FLAGS(type) \ + friend inline DEATH_CONSTEXPR14 type operator|(type a, type b) { return type(((Death::Implementation::__EnumSizedInteger::Type)a) | ((Death::Implementation::__EnumSizedInteger::Type)b)); } \ + friend inline type& operator|=(type& a, type b) { return (type&)(((Death::Implementation::__EnumSizedInteger::Type&)a) |= ((Death::Implementation::__EnumSizedInteger::Type)b)); } \ + friend inline DEATH_CONSTEXPR14 type operator&(type a, type b) { return type(((Death::Implementation::__EnumSizedInteger::Type)a) & ((Death::Implementation::__EnumSizedInteger::Type)b)); } \ + friend inline type& operator&=(type& a, type b) { return (type&)(((Death::Implementation::__EnumSizedInteger::Type&)a) &= ((Death::Implementation::__EnumSizedInteger::Type)b)); } \ + friend inline DEATH_CONSTEXPR14 type operator~(type a) { return type(~((Death::Implementation::__EnumSizedInteger::Type)a)); } \ + friend inline DEATH_CONSTEXPR14 type operator^(type a, type b) { return type(((Death::Implementation::__EnumSizedInteger::Type)a) ^ ((Death::Implementation::__EnumSizedInteger::Type)b)); } \ + friend inline type& operator^=(type& a, type b) { return (type&)(((Death::Implementation::__EnumSizedInteger::Type&)a) ^= ((Death::Implementation::__EnumSizedInteger::Type)b)); } /** @brief Workaround for MSVC not being able to expand `__VA_ARGS__` correctly, would work with `/Zc:preprocessor`. Source: https://stackoverflow.com/a/5134656 */ #define DEATH_HELPER_EXPAND(...) __VA_ARGS__ + /** @brief Pick a macro implementation based on how many arguments were passed. Source: https://stackoverflow.com/a/11763277 */ +#ifdef DOXYGEN_GENERATING_OUTPUT +#define DEATH_HELPER_PICK(...) +#else #define DEATH_HELPER_PICK(_0, _1, _2, _3, _4, _5, _6, _7, macroName, ...) macroName +#endif + /** @brief Get number of arguments in a variadic macro */ #define DEATH_HELPER_ARGS_COUNT(...) DEATH_HELPER_EXPAND(DEATH_HELPER_PICK(__VA_ARGS__, 8, 7, 6, 5, 4, 3, 2, 1, 0)) @@ -66,12 +69,12 @@ namespace Death { namespace Implementation { /** @brief Remove optional parentheses from argument */ #define DEATH_REMOVE_PARENS(x) __DEATH_REMOVE_PARENS_EVALUATE(__DEATH_NOOP, __DEATH_REMOVE_PARENS_EXTRACT x) +#ifndef DOXYGEN_GENERATING_OUTPUT // Compile-time and runtime CPU instruction set dispatch namespace Death { namespace Cpu { class Features; }} -#ifndef DOXYGEN_GENERATING_OUTPUT #if defined(DEATH_CPU_USE_RUNTIME_DISPATCH) && !defined(DEATH_CPU_USE_IFUNC) # define DEATH_CPU_DISPATCHER_DECLARATION(name) decltype(name) name ## Implementation(Cpu::Features); # define DEATH_CPU_DISPATCHER(...) __DEATH_CPU_DISPATCHER(__VA_ARGS__) diff --git a/Sources/Shared/CommonBase.h b/Sources/Shared/CommonBase.h index df7f79bd..354c40c1 100644 --- a/Sources/Shared/CommonBase.h +++ b/Sources/Shared/CommonBase.h @@ -47,13 +47,8 @@ # error DEATH_TARGET_X86 / _ARM / _POWERPC / _RISCV defined on Emscripten #endif -/** - @brief Whether the library is built for a 32-bit target - - Defined if the library is built for a 32-bit target. Not defined on 64-bit platforms. -*/ // 64-bit WebAssembly macro was tested by passing -m64 to emcc -#if !defined(__x86_64) && !defined(_M_X64) && !defined(__aarch64__) && !defined(_M_ARM64) && !defined(__powerpc64__) && !defined(__wasm64__) +#if !defined(__x86_64) && !defined(_M_X64) && !defined(__aarch64__) && !defined(_M_ARM64) && !defined(__powerpc64__) && !defined(__wasm64__) && !defined(DOXYGEN_GENERATING_OUTPUT) # define DEATH_TARGET_32BIT #endif @@ -150,13 +145,6 @@ # define DEATH_TARGET_MINGW #endif -/** - @brief Whether the platform defaults to big-endian - - Defined when the platform defaults to big-endian (such as HP/PA RISC, Motorola 68k, - Big-Endian MIPS, PowerPC and SPARC). Not defined on little-endian platforms (such - as x86 and ARM). This macro only reflects the usual architecture default. -*/ // First checking the GCC/Clang built-in, if available. As a fallback do an architecture-based check, which is mirrored // from SDL_endian.h. Doing this *properly* would mean we can't decide this at compile time as some architectures allow // switching endianness at runtime (and worse, have per-page endianness). So let's pretend we never saw this article: @@ -171,7 +159,7 @@ defined(__m68k__) || defined(mc68000) || defined(_M_M68K) || \ (defined(__MIPS__) && defined(__MIPSEB__)) || \ defined(__ppc__) || defined(__POWERPC__) || defined(_M_PPC) || \ - defined(__sparc__) || defined(DOXYGEN_GENERATING_OUTPUT) + defined(__sparc__) # define DEATH_TARGET_BIG_ENDIAN #endif @@ -343,7 +331,7 @@ Defined on platforms where the @cpp long double @ce type has a 64-bit precision instead of 80-bit, thus same as @cpp double @ce. It's the case for @ref DEATH_TARGET_MSVC "MSVC" ([source](https://docs.microsoft.com/en-us/previous-versions/9cx8xs15(v=vs.140))), - 32-bit @ref DEATH_TARGET_ANDROID "Android" (no reliable source found, sorry), @ref DEATH_TARGET_EMSCRIPTEN "Emscripten" + 32-bit @ref DEATH_TARGET_ANDROID "Android", @ref DEATH_TARGET_EMSCRIPTEN "Emscripten" and @ref DEATH_TARGET_APPLE "Mac" (but not @ref DEATH_TARGET_IOS "iOS") with @ref DEATH_TARGET_ARM "ARM" processors. Emscripten is a bit special because it's @cpp long double @ce is sometimes 80-bit, but its precision differs from the 80-bit representation elsewhere, so it's always treated as 64-bit. @@ -607,7 +595,7 @@ #endif /** - @brief Passthrough (expands to all arguments passed to it) + @brief Passthrough Expands to all arguments passed to it. Inverse of @ref DEATH_NOOP(). */ @@ -616,7 +604,7 @@ #endif /** - @brief No-op (eats all arguments passed to it) + @brief No-op Eats all arguments passed to it. Inverse of @ref DEATH_PASSTHROUGH(). Useful on compilers that don't support defining function macros on command line diff --git a/Sources/Shared/Containers/Array.h b/Sources/Shared/Containers/Array.h index d7f64fa3..ab888e23 100644 --- a/Sources/Shared/Containers/Array.h +++ b/Sources/Shared/Containers/Array.h @@ -714,7 +714,7 @@ namespace Death { namespace Containers { D _deleter; }; - /** + /** @relatesalso Array @brief Construct a list-initialized array Convenience shortcut to the @ref Array::Array(InPlaceInitT, ArrayView) @@ -725,7 +725,7 @@ namespace Death { namespace Containers { return Array{InPlaceInit, list}; } - /** + /** @relatesalso Array @brief Construct a list-initialized array Convenience shortcut to the @ref Array::Array(InPlaceInitT, std::initializer_list) @@ -736,7 +736,7 @@ namespace Death { namespace Containers { return Array{InPlaceInit, list}; } - /** + /** @relatesalso ArrayView @brief Make a view on an @ref Array Convenience alternative to converting to an @ref ArrayView explicitly. @@ -745,7 +745,7 @@ namespace Death { namespace Containers { return ArrayView{array}; } - /** + /** @relatesalso ArrayView @brief Make a view on a const @ref Array Convenience alternative to converting to an @ref ArrayView explicitly. @@ -754,7 +754,9 @@ namespace Death { namespace Containers { return ArrayView{array}; } - /** @brief Reinterpret-cast an array */ + /** @relatesalso Array + @brief Reinterpret-cast an array + */ template inline ArrayView arrayCast(Array& array) { return arrayCast(arrayView(array)); } diff --git a/Sources/Shared/Containers/ArrayView.h b/Sources/Shared/Containers/ArrayView.h index 55d510f7..7bb8bc1d 100644 --- a/Sources/Shared/Containers/ArrayView.h +++ b/Sources/Shared/Containers/ArrayView.h @@ -584,7 +584,7 @@ namespace Death { namespace Containers { std::size_t _size; }; - /** + /** @relatesalso ArrayView @brief Make a view on an array of specific length Convenience alternative to @ref ArrayView::ArrayView(T*, std::size_t). @@ -593,7 +593,7 @@ namespace Death { namespace Containers { return ArrayView{data, size}; } - /** + /** @relatesalso ArrayView @brief Make a view on fixed-size array Convenience alternative to @ref ArrayView::ArrayView(U(&)[size]). @@ -602,7 +602,7 @@ namespace Death { namespace Containers { return ArrayView{data}; } - /** + /** @relatesalso ArrayView @brief Make a view on an initializer list Not present as a constructor in order to avoid accidental dangling references @@ -612,7 +612,7 @@ namespace Death { namespace Containers { return ArrayView{list.begin(), list.size()}; } - /** + /** @relatesalso ArrayView @brief Make a view on @ref StaticArrayView Convenience alternative to @ref ArrayView::ArrayView(StaticArrayView). @@ -621,7 +621,7 @@ namespace Death { namespace Containers { return ArrayView{view}; } - /** + /** @relatesalso ArrayView @brief Make a view on a view Equivalent to the implicit @ref ArrayView copy constructor --- it shouldn't be @@ -631,12 +631,14 @@ namespace Death { namespace Containers { return view; } - /** @brief Make a view on an external type / from an external representation */ + /** @relatesalso ArrayView + @brief Make a view on an external type / from an external representation + */ template::type>::from(std::declval()))> constexpr U arrayView(T&& other) { return Implementation::ErasedArrayViewConverter::type>::from(std::forward(other)); } - /** + /** @relatesalso ArrayView @brief Reinterpret-cast an array view Size of the new array is calculated as @cpp view.size()*sizeof(T)/sizeof(U) @ce. @@ -652,7 +654,7 @@ namespace Death { namespace Containers { return { reinterpret_cast(view.begin()), size }; } - /** + /** @relatesalso ArrayView @brief Reinterpret-cast a void array view Size of the new array is calculated as @cpp view.size()/sizeof(U) @ce. @@ -667,13 +669,21 @@ namespace Death { namespace Containers { return { reinterpret_cast(view.data()), size }; } - /** @overload */ + /** @relatesalso ArrayView + @overload + */ template ArrayView arrayCast(ArrayView view) { auto out = arrayCast(ArrayView{view}); return ArrayView{const_cast(out.data()), out.size()}; } - /** @brief Array view size */ + /** @relatesalso ArrayView + @brief Array view size + + Alias to @ref ArrayView::size(). See also @ref arraySize(T(&)[size_]) for + querying size of a C array and @ref arraySize(U(T::*)[size_]) for querying size + of a C array member. + */ template constexpr std::size_t arraySize(ArrayView view) { return view.size(); } @@ -980,7 +990,7 @@ namespace Death { namespace Containers { T* _data; }; - /** + /** @relatesalso StaticArrayView @brief Make a static view on an array Convenience alternative to @ref StaticArrayView::StaticArrayView(T*). @@ -989,7 +999,7 @@ namespace Death { namespace Containers { return StaticArrayView{data}; } - /** + /** @relatesalso StaticArrayView @brief Make a static view on a fixed-size array Convenience alternative to @ref StaticArrayView::StaticArrayView(U(&)[size_]). @@ -998,7 +1008,7 @@ namespace Death { namespace Containers { return StaticArrayView{data}; } - /** + /** @relatesalso StaticArrayView @brief Make a static view on a view Equivalent to the implicit @ref StaticArrayView copy constructor --- it @@ -1008,12 +1018,14 @@ namespace Death { namespace Containers { return view; } - /** @brief Make a static view on an external type / from an external representation */ + /** @relatesalso StaticArrayView + @brief Make a static view on an external type / from an external representation + */ template::type>::from(std::declval()))> constexpr U staticArrayView(T&& other) { return Implementation::ErasedStaticArrayViewConverter::type>::from(std::forward(other)); } - /** + /** @relatesalso StaticArrayView @brief Reinterpret-cast a static array view Size of the new array is calculated as @cpp view.size()*sizeof(T)/sizeof(U) @ce. @@ -1028,7 +1040,7 @@ namespace Death { namespace Containers { return StaticArrayView{reinterpret_cast(view.begin())}; } - /** + /** @relatesalso StaticArrayView @brief Reinterpret-cast a statically sized array Calls @ref arrayCast(StaticArrayView) with the argument converted to diff --git a/Sources/Shared/Containers/Reference.h b/Sources/Shared/Containers/Reference.h index 686dd3ed..52d606b1 100644 --- a/Sources/Shared/Containers/Reference.h +++ b/Sources/Shared/Containers/Reference.h @@ -114,4 +114,18 @@ namespace Death { namespace Containers { T* _reference; }; + + /** @relatesalso Reference + @brief Make a reference wrapper + + Convenience alternative to @ref Reference::Reference(T&). + + Useful for example when iterating a list of variables that need to be modified + in-place, and where the code would otherwise have to be extra verbose or would + fall back to raw pointers and risk them getting @cpp nullptr @ce. + */ + template constexpr Reference reference(T& reference) { + return Reference{reference}; + } + }} diff --git a/Sources/Shared/Containers/StringView.h b/Sources/Shared/Containers/StringView.h index 6e6a6fbe..420e7fc2 100644 --- a/Sources/Shared/Containers/StringView.h +++ b/Sources/Shared/Containers/StringView.h @@ -983,8 +983,7 @@ namespace Death { namespace Containers { # pragma clang diagnostic ignored "-Wdeprecated-literal-operator" #endif - /** - @relatesalso Death::Containers::BasicStringView + /** @relatesalso Death::Containers::BasicStringView @brief String view literal The returned instance has both @ref StringViewFlags::Global and @ref StringViewFlags::NullTerminated set. diff --git a/Sources/nCine/Audio/IAudioPlayer.h b/Sources/nCine/Audio/IAudioPlayer.h index 3f5f8f51..d45e7408 100644 --- a/Sources/nCine/Audio/IAudioPlayer.h +++ b/Sources/nCine/Audio/IAudioPlayer.h @@ -138,7 +138,7 @@ namespace nCine As2D = 0x04 }; - DEFINE_PRIVATE_ENUM_OPERATORS(PlayerFlags); + DEATH_PRIVATE_ENUM_FLAGS(PlayerFlags); /// The OpenAL source id unsigned int sourceId_;