diff --git a/Sources/Jazz2/Actors/Multiplayer/RemotablePlayer.cpp b/Sources/Jazz2/Actors/Multiplayer/RemotablePlayer.cpp index 6c4b3f35..5b98af76 100644 --- a/Sources/Jazz2/Actors/Multiplayer/RemotablePlayer.cpp +++ b/Sources/Jazz2/Actors/Multiplayer/RemotablePlayer.cpp @@ -26,6 +26,10 @@ namespace Jazz2::Actors::Multiplayer void RemotablePlayer::OnUpdate(float timeMult) { Player::OnUpdate(timeMult); + + if (_levelExiting != LevelExitingState::None) { + OnLevelChanging(nullptr, ExitType::None); + } } void RemotablePlayer::OnWaterSplash(const Vector2f& pos, bool inwards) @@ -52,8 +56,13 @@ namespace Jazz2::Actors::Multiplayer _teamId = value; } - void RemotablePlayer::WarpIn() + void RemotablePlayer::WarpIn(ExitType exitType) { + if (exitType != (ExitType)0xFF) { + OnLevelChanging(this, exitType); + return; + } + EndDamagingMove(); SetState(ActorState::IsInvulnerable, true); SetState(ActorState::ApplyGravitation, false); diff --git a/Sources/Jazz2/Actors/Multiplayer/RemotablePlayer.h b/Sources/Jazz2/Actors/Multiplayer/RemotablePlayer.h index 95c1a43c..cb6c9123 100644 --- a/Sources/Jazz2/Actors/Multiplayer/RemotablePlayer.h +++ b/Sources/Jazz2/Actors/Multiplayer/RemotablePlayer.h @@ -16,7 +16,7 @@ namespace Jazz2::Actors::Multiplayer std::uint8_t GetTeamId() const; void SetTeamId(std::uint8_t value); - void WarpIn(); + void WarpIn(ExitType exitType); void MoveRemotely(const Vector2f& pos, const Vector2f& speed); protected: diff --git a/Sources/Jazz2/Actors/Multiplayer/RemotePlayerOnServer.cpp b/Sources/Jazz2/Actors/Multiplayer/RemotePlayerOnServer.cpp index 67d99399..a398dfd6 100644 --- a/Sources/Jazz2/Actors/Multiplayer/RemotePlayerOnServer.cpp +++ b/Sources/Jazz2/Actors/Multiplayer/RemotePlayerOnServer.cpp @@ -72,9 +72,23 @@ namespace Jazz2::Actors::Multiplayer bool RemotePlayerOnServer::OnHandleCollision(std::shared_ptr other) { + // TODO: Remove this override return PlayerOnServer::OnHandleCollision(other); } + bool RemotePlayerOnServer::OnLevelChanging(Actors::ActorBase* initiator, ExitType exitType) + { + LevelExitingState lastState = _levelExiting; + bool success = PlayerOnServer::OnLevelChanging(initiator, exitType); + + if (lastState == LevelExitingState::None) { + // Level changing just started, send the request to the player as WarpIn packet + static_cast(_levelHandler)->HandlePlayerLevelChanging(this, exitType); + } + + return success; + } + void RemotePlayerOnServer::SyncWithServer(const Vector2f& pos, const Vector2f& speed, bool isVisible, bool isFacingLeft, bool isActivelyPushing) { Clock& c = nCine::clock(); diff --git a/Sources/Jazz2/Actors/Multiplayer/RemotePlayerOnServer.h b/Sources/Jazz2/Actors/Multiplayer/RemotePlayerOnServer.h index 2383037f..7638bac4 100644 --- a/Sources/Jazz2/Actors/Multiplayer/RemotePlayerOnServer.h +++ b/Sources/Jazz2/Actors/Multiplayer/RemotePlayerOnServer.h @@ -14,6 +14,7 @@ namespace Jazz2::Actors::Multiplayer RemotePlayerOnServer(); bool OnHandleCollision(std::shared_ptr other) override; + bool OnLevelChanging(Actors::ActorBase* initiator, ExitType exitType) override; void SyncWithServer(const Vector2f& pos, const Vector2f& speed, bool isVisible, bool isFacingLeft, bool isActivelyPushing); diff --git a/Sources/Jazz2/Actors/Player.h b/Sources/Jazz2/Actors/Player.h index 9a84e068..72092f81 100644 --- a/Sources/Jazz2/Actors/Player.h +++ b/Sources/Jazz2/Actors/Player.h @@ -115,7 +115,7 @@ namespace Jazz2::Actors bool CanBreakSolidObjects() const; bool CanMoveVertically() const; - bool OnLevelChanging(Actors::ActorBase* initiator, ExitType exitType); + virtual bool OnLevelChanging(Actors::ActorBase* initiator, ExitType exitType); void ReceiveLevelCarryOver(ExitType exitType, const PlayerCarryOver& carryOver); PlayerCarryOver PrepareLevelCarryOver(); void InitializeFromStream(ILevelHandler* levelHandler, Stream& src); diff --git a/Sources/Jazz2/Multiplayer/MultiLevelHandler.cpp b/Sources/Jazz2/Multiplayer/MultiLevelHandler.cpp index a635e295..e9a58be0 100644 --- a/Sources/Jazz2/Multiplayer/MultiLevelHandler.cpp +++ b/Sources/Jazz2/Multiplayer/MultiLevelHandler.cpp @@ -58,7 +58,7 @@ namespace Jazz2::Multiplayer _ignorePackets(false) #if defined(DEATH_DEBUG) && defined(WITH_IMGUI) , _plotIndex(0), _actorsMaxCount(0.0f), _actorsCount{}, _remoteActorsCount{}, _remotingActorsCount{}, - _mirroredActorsCount{}, _updatePacketMaxSize(0.0f), _updatePacketSize {}, _compressedUpdatePacketSize {} + _mirroredActorsCount{}, _updatePacketMaxSize(0.0f), _updatePacketSize{}, _compressedUpdatePacketSize{} #endif { _isServer = (networkManager->GetState() == NetworkState::Listening); @@ -94,7 +94,7 @@ namespace Jazz2::Multiplayer packet.WriteVariableUint32(_levelFileName.size()); packet.Write(_levelFileName.data(), _levelFileName.size()); // TODO: Send it to only authenticated peers - _networkManager->SendToAll(NetworkChannel::Main, packet.GetBuffer(), packet.GetSize()); + _networkManager->SendToAll(NetworkChannel::Main, packet); } auto& resolver = ContentResolver::Get(); @@ -106,6 +106,7 @@ namespace Jazz2::Multiplayer float MultiLevelHandler::GetDefaultAmbientLight() const { + // TODO: Remove this override return LevelHandler::GetDefaultAmbientLight(); } @@ -128,11 +129,11 @@ namespace Jazz2::Multiplayer auto& input = _playerInputs[0]; if (input.PressedActions != input.PressedActionsLast) { - MemoryStream packet(9); + MemoryStream packet(13); packet.WriteValue((std::uint8_t)ClientPacketType::PlayerKeyPress); packet.WriteVariableUint32(_lastSpawnedActorId); packet.WriteVariableUint64(input.PressedActions); - _networkManager->SendToPeer(nullptr, NetworkChannel::UnreliableUpdates, packet.GetBuffer(), packet.GetSize()); + _networkManager->SendToPeer(nullptr, NetworkChannel::UnreliableUpdates, packet); } } @@ -141,9 +142,14 @@ namespace Jazz2::Multiplayer LevelHandler::OnEndFrame(); float timeMult = theApplication().GetTimeMult(); + std::uint32_t frameCount = theApplication().GetFrameCount(); + // Update last pressed keys only if it wasn't done this frame yet (because of PlayerKeyPress packet) for (auto& [playerIndex, playerState] : _playerStates) { - playerState.PressedKeysLast |= playerState.PressedKeys; + if (playerState.UpdatedFrame != frameCount) { + playerState.UpdatedFrame = frameCount; + playerState.PressedKeysLast = playerState.PressedKeys; + } } _updateTimeLeft -= timeMult; @@ -154,9 +160,9 @@ namespace Jazz2::Multiplayer _initialUpdateSent = true; if (!_isServer) { - MemoryStream packet(5); + MemoryStream packet(1); packet.WriteValue((std::uint8_t)ClientPacketType::LevelReady); - _networkManager->SendToPeer(nullptr, NetworkChannel::Main, packet.GetBuffer(), packet.GetSize()); + _networkManager->SendToPeer(nullptr, NetworkChannel::Main, packet); } } @@ -174,7 +180,7 @@ namespace Jazz2::Multiplayer bool isMirrored = (_isServer ? ActorShouldBeMirrored(actor.second.get()) - : runtime_cast(actor.second) == nullptr); + : !runtime_cast(actor.second)); if (isMirrored) { _mirroredActorsCount[_plotIndex]++; @@ -189,7 +195,6 @@ namespace Jazz2::Multiplayer std::uint32_t actorCount = (std::uint32_t)(_players.size() + _remotingActors.size()); MemoryStream packet(5 + actorCount * 19); - //packet.WriteValue((std::uint8_t)ServerPacketType::UpdateAllActors); packet.WriteVariableUint32(actorCount); for (Actors::Player* player : _players) { @@ -282,7 +287,7 @@ namespace Jazz2::Multiplayer _compressedUpdatePacketSize[_plotIndex] = packetCompressed.GetSize(); #endif - _networkManager->SendToAll(NetworkChannel::UnreliableUpdates, packetCompressed.GetBuffer(), packetCompressed.GetSize()); + _networkManager->SendToAll(NetworkChannel::UnreliableUpdates, packetCompressed); SynchronizePeers(); } else { @@ -323,10 +328,11 @@ namespace Jazz2::Multiplayer #if defined(DEATH_DEBUG) && defined(WITH_IMGUI) _updatePacketSize[_plotIndex] = packet.GetSize(); + _compressedUpdatePacketSize[_plotIndex] = _updatePacketSize[_plotIndex]; _updatePacketMaxSize = std::max(_updatePacketMaxSize, _updatePacketSize[_plotIndex]); #endif - _networkManager->SendToPeer(nullptr, NetworkChannel::UnreliableUpdates, packet.GetBuffer(), packet.GetSize()); + _networkManager->SendToPeer(nullptr, NetworkChannel::UnreliableUpdates, packet); } } } @@ -453,7 +459,7 @@ namespace Jazz2::Multiplayer packet.WriteVariableInt32((std::int32_t)actorPtr->_renderer.layer()); // TODO: If it fail, it will release the packet which is wrong - _networkManager->SendToPeer(peer, NetworkChannel::Main, packet.GetBuffer(), packet.GetSize()); + _networkManager->SendToPeer(peer, NetworkChannel::Main, packet); } } } else { @@ -472,7 +478,7 @@ namespace Jazz2::Multiplayer packet.WriteVariableUint32((std::uint32_t)(actorPtr->_currentTransition != nullptr ? actorPtr->_currentTransition->State : actorPtr->_currentAnimation->State)); // TODO: If it fail, it will release the packet which is wrong - _networkManager->SendToPeer(peer, NetworkChannel::Main, packet.GetBuffer(), packet.GetSize()); + _networkManager->SendToPeer(peer, NetworkChannel::Main, packet); } } } @@ -508,7 +514,7 @@ namespace Jazz2::Multiplayer packet.Write(identifier.data(), (std::uint32_t)identifier.size()); // TODO: If it fails, it will release the packet which is wrong - _networkManager->SendToPeer(peer, NetworkChannel::Main, packet.GetBuffer(), packet.GetSize()); + _networkManager->SendToPeer(peer, NetworkChannel::Main, packet); } } } @@ -531,7 +537,7 @@ namespace Jazz2::Multiplayer packet.Write(identifier.data(), (std::uint32_t)identifier.size()); // TODO: If it fails, it will release the packet which is wrong - _networkManager->SendToPeer(peer, NetworkChannel::Main, packet.GetBuffer(), packet.GetSize()); + _networkManager->SendToPeer(peer, NetworkChannel::Main, packet); } } @@ -586,9 +592,27 @@ namespace Jazz2::Multiplayer bool MultiLevelHandler::HandlePlayerDied(Actors::Player* player) { + // TODO: Remove this override return LevelHandler::HandlePlayerDied(player); } + void MultiLevelHandler::HandlePlayerLevelChanging(Actors::Player* player, ExitType exitType) + { + // TODO: Only called by RemotePlayerOnServer + if (_isServer) { + for (const auto& [peer, peerDesc] : _peerDesc) { + if (peerDesc.Player == player) { + MemoryStream packet(6); + packet.WriteValue((std::uint8_t)ServerPacketType::PlayerWarpIn); + packet.WriteVariableUint32(player->_playerIndex); + packet.WriteValue((std::uint8_t)exitType); + _networkManager->SendToPeer(peer, NetworkChannel::Main, packet); + break; + } + } + } + } + bool MultiLevelHandler::HandlePlayerSpring(Actors::Player* player, const Vector2f& pos, const Vector2f& force, bool keepSpeedX, bool keepSpeedY) { // TODO: Only called by RemotePlayerOnServer @@ -611,7 +635,7 @@ namespace Jazz2::Multiplayer packet.WriteValue((std::int16_t)(force.X * 512.0f)); packet.WriteValue((std::int16_t)(force.Y * 512.0f)); packet.WriteValue(flags); - _networkManager->SendToPeer(peer, NetworkChannel::Main, packet.GetBuffer(), packet.GetSize()); + _networkManager->SendToPeer(peer, NetworkChannel::Main, packet); break; } } @@ -637,10 +661,11 @@ namespace Jazz2::Multiplayer for (const auto& [peer, peerDesc] : _peerDesc) { if (peerDesc.Player == player) { - MemoryStream packet(5); + MemoryStream packet(6); packet.WriteValue((std::uint8_t)ServerPacketType::PlayerWarpIn); packet.WriteVariableUint32(player->_playerIndex); - _networkManager->SendToPeer(peer, NetworkChannel::Main, packet.GetBuffer(), packet.GetSize()); + packet.WriteValue(0xFF); // Only temporary, no level changing + _networkManager->SendToPeer(peer, NetworkChannel::Main, packet); break; } } @@ -657,7 +682,7 @@ namespace Jazz2::Multiplayer packet.WriteVariableUint32(player->_playerIndex); packet.WriteVariableInt32(player->_health); packet.WriteValue((std::int16_t)(pushForce * 512.0f)); - _networkManager->SendToPeer(peer, NetworkChannel::Main, packet.GetBuffer(), packet.GetSize()); + _networkManager->SendToPeer(peer, NetworkChannel::Main, packet); break; } } @@ -675,7 +700,7 @@ namespace Jazz2::Multiplayer packet.WriteVariableUint32(player->_playerIndex); packet.WriteValue((std::uint8_t)player->_currentWeapon); packet.WriteValue((std::uint16_t)player->_weaponAmmo[(std::uint8_t)player->_currentWeapon]); - _networkManager->SendToPeer(peer, NetworkChannel::Main, packet.GetBuffer(), packet.GetSize()); + _networkManager->SendToPeer(peer, NetworkChannel::Main, packet); break; } } @@ -693,7 +718,7 @@ namespace Jazz2::Multiplayer packet.WriteVariableUint32(player->_playerIndex); packet.WriteValue((std::uint8_t)player->_currentWeapon); packet.WriteValue((std::uint8_t)player->_weaponUpgrades[(std::uint8_t)player->_currentWeapon]); - _networkManager->SendToPeer(peer, NetworkChannel::Main, packet.GetBuffer(), packet.GetSize()); + _networkManager->SendToPeer(peer, NetworkChannel::Main, packet); break; } } @@ -710,7 +735,7 @@ namespace Jazz2::Multiplayer packet.WriteValue((std::uint8_t)ServerPacketType::PlayerChangeWeapon); packet.WriteVariableUint32(player->_playerIndex); packet.WriteValue((std::uint8_t)player->_currentWeapon); - _networkManager->SendToPeer(peer, NetworkChannel::Main, packet.GetBuffer(), packet.GetSize()); + _networkManager->SendToPeer(peer, NetworkChannel::Main, packet); break; } } @@ -740,7 +765,7 @@ namespace Jazz2::Multiplayer packet.WriteValue((std::int32_t)(player->_pos.Y * 512.0f)); packet.WriteValue((std::int16_t)(player->_speed.X * 512.0f)); packet.WriteValue((std::int16_t)(player->_speed.Y * 512.0f)); - _networkManager->SendToPeer(peer, NetworkChannel::Main, packet.GetBuffer(), packet.GetSize()); + _networkManager->SendToPeer(peer, NetworkChannel::Main, packet); break; } } @@ -758,7 +783,7 @@ namespace Jazz2::Multiplayer packet.WriteValue((std::uint8_t)ServerPacketType::PlayerRefreshCoins); packet.WriteVariableUint32(player->_playerIndex); packet.WriteVariableInt32(newCount); - _networkManager->SendToPeer(peer, NetworkChannel::Main, packet.GetBuffer(), packet.GetSize()); + _networkManager->SendToPeer(peer, NetworkChannel::Main, packet); break; } } @@ -776,7 +801,7 @@ namespace Jazz2::Multiplayer packet.WriteValue((std::uint8_t)ServerPacketType::PlayerRefreshGems); packet.WriteVariableUint32(player->_playerIndex); packet.WriteVariableInt32(newCount); - _networkManager->SendToPeer(peer, NetworkChannel::Main, packet.GetBuffer(), packet.GetSize()); + _networkManager->SendToPeer(peer, NetworkChannel::Main, packet); break; } } @@ -821,7 +846,7 @@ namespace Jazz2::Multiplayer packet.WriteVariableUint32(textLength); packet.Write(value.data(), textLength); - _networkManager->SendToPeer(nullptr, NetworkChannel::Main, packet.GetBuffer(), packet.GetSize()); + _networkManager->SendToPeer(nullptr, NetworkChannel::Main, packet); } } @@ -923,7 +948,7 @@ namespace Jazz2::Multiplayer packet.WriteVariableInt32(ty); packet.WriteVariableInt32(amount); - _networkManager->SendToAll(NetworkChannel::Main, packet.GetBuffer(), packet.GetSize()); + _networkManager->SendToAll(NetworkChannel::Main, packet); } } @@ -1015,7 +1040,7 @@ namespace Jazz2::Multiplayer packet.WriteValue((std::uint8_t)_gameMode); // TODO: If it fail, it will release the packet which is wrong - _networkManager->SendToPeer(peer, NetworkChannel::Main, packet.GetBuffer(), packet.GetSize()); + _networkManager->SendToPeer(peer, NetworkChannel::Main, packet); } return true; @@ -1051,7 +1076,7 @@ namespace Jazz2::Multiplayer packet.WriteVariableUint32(playerIndex); // TODO: If it fails, it will release the packet which is wrong - _networkManager->SendToPeer(otherPeer, NetworkChannel::Main, packet.GetBuffer(), packet.GetSize()); + _networkManager->SendToPeer(otherPeer, NetworkChannel::Main, packet); } } return true; @@ -1086,7 +1111,7 @@ namespace Jazz2::Multiplayer packet.WriteVariableUint32(_levelFileName.size()); packet.Write(_levelFileName.data(), _levelFileName.size()); - _networkManager->SendToPeer(peer, NetworkChannel::Main, packet.GetBuffer(), packet.GetSize()); + _networkManager->SendToPeer(peer, NetworkChannel::Main, packet); return true; } case ClientPacketType::LevelReady: { @@ -1136,7 +1161,7 @@ namespace Jazz2::Multiplayer packet2.WriteVariableUint32(playerIndex); packet2.WriteVariableUint64(seqNumWarped); - _networkManager->SendToPeer(peer, NetworkChannel::Main, packet2.GetBuffer(), packet2.GetSize()); + _networkManager->SendToPeer(peer, NetworkChannel::Main, packet2); } } @@ -1178,7 +1203,7 @@ namespace Jazz2::Multiplayer packet2.WriteValue((std::int32_t)(posY * 512.0f)); packet2.WriteValue((std::int16_t)(player->_speed.X * 512.0f)); packet2.WriteValue((std::int16_t)(player->_speed.Y * 512.0f)); - _networkManager->SendToPeer(peer, NetworkChannel::Main, packet2.GetBuffer(), packet2.GetSize()); + _networkManager->SendToPeer(peer, NetworkChannel::Main, packet2); } }*/ @@ -1201,7 +1226,11 @@ namespace Jazz2::Multiplayer return true; } - it->second.PressedKeysLast = it->second.PressedKeys; + std::uint32_t frameCount = theApplication().GetFrameCount(); + if (it->second.UpdatedFrame != frameCount) { + it->second.UpdatedFrame = frameCount; + it->second.PressedKeysLast = it->second.PressedKeys; + } it->second.PressedKeys = packet.ReadVariableUint64(); //LOGD("Player %i pressed 0x%08x, last state was 0x%08x", playerIndex, it->second.PressedKeys & 0xffffffffu, prevState); @@ -1577,10 +1606,11 @@ namespace Jazz2::Multiplayer return true; } - LOGD("ServerPacketType::PlayerWarpIn received - playerIndex: %u", playerIndex); + ExitType exitType = (ExitType)packet.ReadValue(); + LOGD("ServerPacketType::PlayerWarpIn received - playerIndex: %u, exitType: 0x%02x", playerIndex, exitType); - _root->InvokeAsync([this]() { - static_cast(_players[0])->WarpIn(); + _root->InvokeAsync([this, exitType]() { + static_cast(_players[0])->WarpIn(exitType); }); return true; } @@ -1618,7 +1648,7 @@ namespace Jazz2::Multiplayer packet.WriteValue(triggerId); packet.WriteValue(newState); - _networkManager->SendToAll(NetworkChannel::Main, packet.GetBuffer(), packet.GetSize()); + _networkManager->SendToAll(NetworkChannel::Main, packet); } } @@ -1653,7 +1683,7 @@ namespace Jazz2::Multiplayer packet.WriteVariableUint32(actorId); // TODO: If it fails, it will release the packet which is wrong - _networkManager->SendToPeer(peer, NetworkChannel::Main, packet.GetBuffer(), packet.GetSize()); + _networkManager->SendToPeer(peer, NetworkChannel::Main, packet); } _remotingActors.erase(it); @@ -1720,7 +1750,7 @@ namespace Jazz2::Multiplayer MemoryStream packet(20 * 1024); packet.WriteValue((std::uint8_t)ServerPacketType::SyncTileMap); _tileMap->SerializeResumableToStream(packet); - _networkManager->SendToPeer(peer, NetworkChannel::Main, packet.GetBuffer(), packet.GetSize()); + _networkManager->SendToPeer(peer, NetworkChannel::Main, packet); } // Spawn the player also on the remote side @@ -1740,7 +1770,7 @@ namespace Jazz2::Multiplayer packet.WriteVariableInt32((std::int32_t)player->_pos.X); packet.WriteVariableInt32((std::int32_t)player->_pos.Y); - _networkManager->SendToPeer(peer, NetworkChannel::Main, packet.GetBuffer(), packet.GetSize()); + _networkManager->SendToPeer(peer, NetworkChannel::Main, packet); } for (Actors::Player* otherPlayer : _players) { @@ -1762,7 +1792,7 @@ namespace Jazz2::Multiplayer packet.WriteVariableUint32((std::uint32_t)(otherPlayer->_currentTransition != nullptr ? otherPlayer->_currentTransition->State : otherPlayer->_currentAnimation->State)); // TODO: If it fail, it will release the packet which is wrong - _networkManager->SendToPeer(peer, NetworkChannel::Main, packet.GetBuffer(), packet.GetSize()); + _networkManager->SendToPeer(peer, NetworkChannel::Main, packet); } for (const auto& [remotingActor, remotingActorId] : _remotingActors) { @@ -1782,7 +1812,7 @@ namespace Jazz2::Multiplayer packet.WriteVariableInt32((std::int32_t)remotingActor->_renderer.layer()); // TODO: If it fail, it will release the packet which is wrong - _networkManager->SendToPeer(peer, NetworkChannel::Main, packet.GetBuffer(), packet.GetSize()); + _networkManager->SendToPeer(peer, NetworkChannel::Main, packet); } } } else { @@ -1800,7 +1830,7 @@ namespace Jazz2::Multiplayer packet.WriteVariableUint32((std::uint32_t)(remotingActor->_currentTransition != nullptr ? remotingActor->_currentTransition->State : remotingActor->_currentAnimation->State)); // TODO: If it fail, it will release the packet which is wrong - _networkManager->SendToPeer(peer, NetworkChannel::Main, packet.GetBuffer(), packet.GetSize()); + _networkManager->SendToPeer(peer, NetworkChannel::Main, packet); } } @@ -1823,7 +1853,7 @@ namespace Jazz2::Multiplayer packet.WriteVariableUint32((std::uint32_t)(player->_currentTransition != nullptr ? player->_currentTransition->State : player->_currentAnimation->State)); // TODO: If it fails, it will release the packet which is wrong - _networkManager->SendToPeer(otherPeer, NetworkChannel::Main, packet.GetBuffer(), packet.GetSize()); + _networkManager->SendToPeer(otherPeer, NetworkChannel::Main, packet); } } } @@ -2096,7 +2126,7 @@ namespace Jazz2::Multiplayer } MultiLevelHandler::PlayerState::PlayerState(const Vector2f& pos, const Vector2f& speed) - : Flags(PlayerFlags::None), PressedKeys(0), PressedKeysLast(0)/*, WarpSeqNum(0), WarpTimeLeft(0.0f)*/ + : Flags(PlayerFlags::None), PressedKeys(0), PressedKeysLast(0), UpdatedFrame(0)/*, WarpSeqNum(0), WarpTimeLeft(0.0f)*/ { } } diff --git a/Sources/Jazz2/Multiplayer/MultiLevelHandler.h b/Sources/Jazz2/Multiplayer/MultiLevelHandler.h index ee626c28..9b209faa 100644 --- a/Sources/Jazz2/Multiplayer/MultiLevelHandler.h +++ b/Sources/Jazz2/Multiplayer/MultiLevelHandler.h @@ -100,6 +100,7 @@ namespace Jazz2::Multiplayer void ProcessEvents(float timeMult) override; void PrepareNextLevelInitialization(LevelInitialization& levelInit) override; + void HandlePlayerLevelChanging(Actors::Player* player, ExitType exitType); bool HandlePlayerSpring(Actors::Player* player, const Vector2f& pos, const Vector2f& force, bool keepSpeedX, bool keepSpeedY); void HandlePlayerBeforeWarp(Actors::Player* player, const Vector2f& pos, WarpFlags flags); void HandlePlayerTakeDamage(Actors::Player* player, std::int32_t amount, float pushForce); @@ -141,6 +142,7 @@ namespace Jazz2::Multiplayer PlayerFlags Flags; std::uint64_t PressedKeys; std::uint64_t PressedKeysLast; + std::uint32_t UpdatedFrame; //std::uint64_t WarpSeqNum; //float WarpTimeLeft; diff --git a/Sources/Jazz2/Multiplayer/NetworkManager.cpp b/Sources/Jazz2/Multiplayer/NetworkManager.cpp index 7a84d2c6..d45ae53b 100644 --- a/Sources/Jazz2/Multiplayer/NetworkManager.cpp +++ b/Sources/Jazz2/Multiplayer/NetworkManager.cpp @@ -143,6 +143,11 @@ namespace Jazz2::Multiplayer _lock.Unlock(); } + void NetworkManager::SendToPeer(const Peer& peer, NetworkChannel channel, const MemoryStream& packet) + { + SendToPeer(peer, channel, packet.GetBuffer(), packet.GetSize()); + } + void NetworkManager::SendToAll(NetworkChannel channel, const std::uint8_t* data, std::size_t dataLength) { if (_peers.empty()) { @@ -173,6 +178,11 @@ namespace Jazz2::Multiplayer _lock.Unlock(); } + void NetworkManager::SendToAll(NetworkChannel channel, const MemoryStream& packet) + { + SendToAll(channel, packet.GetBuffer(), packet.GetSize()); + } + void NetworkManager::KickClient(const Peer& peer, Reason reason) { enet_peer_disconnect_now(peer._enet, (std::uint32_t)reason); diff --git a/Sources/Jazz2/Multiplayer/NetworkManager.h b/Sources/Jazz2/Multiplayer/NetworkManager.h index 6e092f97..bef5d852 100644 --- a/Sources/Jazz2/Multiplayer/NetworkManager.h +++ b/Sources/Jazz2/Multiplayer/NetworkManager.h @@ -11,10 +11,12 @@ #include #include +#include struct _ENetHost; using namespace Death::Containers; +using namespace Death::IO; using namespace nCine; namespace Jazz2::Multiplayer @@ -54,7 +56,9 @@ namespace Jazz2::Multiplayer NetworkState GetState() const; void SendToPeer(const Peer& peer, NetworkChannel channel, const std::uint8_t* data, std::size_t dataLength); + void SendToPeer(const Peer& peer, NetworkChannel channel, const MemoryStream& packet); void SendToAll(NetworkChannel channel, const std::uint8_t* data, std::size_t dataLength); + void SendToAll(NetworkChannel channel, const MemoryStream& packet); void KickClient(const Peer& peer, Reason reason); private: diff --git a/Sources/Jazz2/Multiplayer/PacketTypes.h b/Sources/Jazz2/Multiplayer/PacketTypes.h index 083a0013..d72490f6 100644 --- a/Sources/Jazz2/Multiplayer/PacketTypes.h +++ b/Sources/Jazz2/Multiplayer/PacketTypes.h @@ -6,6 +6,13 @@ namespace Jazz2::Multiplayer { + enum class BroadcastPacketType + { + Null, + DiscoveryRequest, + DiscoveryResponse + }; + enum class ClientPacketType { Null, diff --git a/Sources/Jazz2/Multiplayer/Reason.h b/Sources/Jazz2/Multiplayer/Reason.h index ef31fbee..97ead5b0 100644 --- a/Sources/Jazz2/Multiplayer/Reason.h +++ b/Sources/Jazz2/Multiplayer/Reason.h @@ -14,6 +14,9 @@ namespace Jazz2::Multiplayer ServerIsFull, ServerNotReady, ServerStopped, + ServerStoppedForMaintenance, + ServerStoppedForReconfiguration, + ServerStoppedForUpdate, ConnectionLost, ConnectionTimedOut, Kicked, diff --git a/Sources/Jazz2/Multiplayer/ServerDiscovery.cpp b/Sources/Jazz2/Multiplayer/ServerDiscovery.cpp index de0d60fa..31aae359 100644 --- a/Sources/Jazz2/Multiplayer/ServerDiscovery.cpp +++ b/Sources/Jazz2/Multiplayer/ServerDiscovery.cpp @@ -3,6 +3,7 @@ #if defined(WITH_MULTIPLAYER) #include "NetworkManager.h" +#include "PacketTypes.h" #include "../../nCine/Base/Timer.h" #include @@ -97,7 +98,7 @@ namespace Jazz2::Multiplayer { MemoryStream packet(9); packet.WriteValue(PacketSignature); - packet.WriteValue(1); + packet.WriteValue((std::uint8_t)BroadcastPacketType::DiscoveryRequest); ENetBuffer sendbuf; sendbuf.data = (void*)packet.GetBuffer(); @@ -134,8 +135,8 @@ namespace Jazz2::Multiplayer MemoryStream packet(buffer, bytesRead); std::uint64_t signature = packet.ReadValue(); - std::uint8_t packetType = packet.ReadValue(); - if (signature != PacketSignature || packetType != 2) { + BroadcastPacketType packetType = (BroadcastPacketType)packet.ReadValue(); + if (signature != PacketSignature || packetType != BroadcastPacketType::DiscoveryResponse) { return false; } @@ -179,8 +180,8 @@ namespace Jazz2::Multiplayer MemoryStream packet(buffer, bytesRead); std::uint64_t signature = packet.ReadValue(); - std::uint8_t packetType = packet.ReadValue(); - if (signature != PacketSignature || packetType != 1) { + BroadcastPacketType packetType = (BroadcastPacketType)packet.ReadValue(); + if (signature != PacketSignature || packetType != BroadcastPacketType::DiscoveryRequest) { return false; } @@ -201,7 +202,6 @@ namespace Jazz2::Multiplayer ServerDesc discoveredServer; if (ProcessResponses(socket, discoveredServer, 0)) { - LOGW("TODO Process responses"); observer->OnServerFound(std::move(discoveredServer)); } else { // No responses, sleep for a while @@ -233,13 +233,12 @@ namespace Jazz2::Multiplayer if (_this->_lastRequest.secondsSince() > 15) { _this->_lastRequest = TimeStamp::now(); - LOGW("TODO Send responses"); - MemoryStream packet(512); packet.WriteValue(PacketSignature); - packet.WriteValue(2); + packet.WriteValue((std::uint8_t)BroadcastPacketType::DiscoveryResponse); packet.WriteValue(_this->_actualPort); + // TODO: Unique identifier //packet.Write(server->GetUniqueIdentifier(), UniqueIdentifierLength); static const std::uint8_t UniqueIdentifier[16] = { 1, 2, 3, 4, 5, 6 }; packet.Write(UniqueIdentifier, UniqueIdentifierLength); diff --git a/Sources/Main.cpp b/Sources/Main.cpp index 8ffbc089..015359f3 100644 --- a/Sources/Main.cpp +++ b/Sources/Main.cpp @@ -210,7 +210,7 @@ void GameEventHandler::OnPreInitialize(AppConfiguration& config) #endif #if defined(WITH_IMGUI) - config.withDebugOverlay = true; + //config.withDebugOverlay = true; #endif } @@ -499,6 +499,10 @@ void GameEventHandler::ChangeLevel(LevelInitialization&& levelInit) if (levelInit.LevelName.empty()) { // Next level not specified, so show main menu newHandler = std::make_unique(this, false); +#if defined(WITH_MULTIPLAYER) + // TODO: This should show some server console instead of exiting + _networkManager = nullptr; +#endif } else if (levelInit.LevelName == ":end"_s) { // End of episode SaveEpisodeEnd(levelInit); @@ -519,9 +523,17 @@ void GameEventHandler::ChangeLevel(LevelInitialization&& levelInit) auto mainMenu = std::make_unique(this, false); mainMenu->SwitchToSection(_("\f[c:#704a4a]Cannot load specified level!\f[/c]\n\n\nMake sure all necessary files\nare accessible and try it again."), true); newHandler = std::move(mainMenu); +#if defined(WITH_MULTIPLAYER) + // TODO: This should show some server console instead of exiting + _networkManager = nullptr; +#endif } } else { newHandler = std::make_unique(this, false); +#if defined(WITH_MULTIPLAYER) + // TODO: This should show some server console instead of exiting + _networkManager = nullptr; +#endif } } else if (levelInit.LevelName == ":credits"_s) { // End of game @@ -553,6 +565,10 @@ void GameEventHandler::ChangeLevel(LevelInitialization&& levelInit) auto mainMenu = std::make_unique(this, false); mainMenu->SwitchToSection(_("\f[c:#704a4a]Cannot load specified level!\f[/c]\n\n\nMake sure all necessary files\nare accessible and try it again."), true); newHandler = std::move(mainMenu); +#if defined(WITH_MULTIPLAYER) + // TODO: This should show some server console instead of exiting + _networkManager = nullptr; +#endif } } } @@ -739,7 +755,14 @@ void GameEventHandler::OnPeerDisconnected(const Peer& peer, Reason reason) case Reason::IncompatibleVersion: mainMenu->SwitchToSection(_("\f[c:#704a4a]Cannot connect to the server!\f[/c]\n\n\nYour client version is not compatible with the server.")); break; case Reason::ServerIsFull: mainMenu->SwitchToSection(_("\f[c:#704a4a]Cannot connect to the server!\f[/c]\n\n\nServer capacity is full.\nPlease try it later.")); break; case Reason::ServerNotReady: mainMenu->SwitchToSection(_("\f[c:#704a4a]Cannot connect to the server!\f[/c]\n\n\nServer is not in a state where it can process your request.\nPlease try again in a few seconds.")); break; - case Reason::ServerStopped: mainMenu->SwitchToSection(_("\f[c:#704a4a]Connection has been closed!\f[/c]\n\n\nServer is shutting down.\nPlease try it later.")); break; + + // TODO: Add multiplayer disconnect reason messages + case Reason::ServerStopped: + case Reason::ServerStoppedForMaintenance: + case Reason::ServerStoppedForReconfiguration: + case Reason::ServerStoppedForUpdate: + mainMenu->SwitchToSection(_("\f[c:#704a4a]Connection has been closed!\f[/c]\n\n\nServer is shutting down.\nPlease try it later.")); break; + case Reason::ConnectionLost: mainMenu->SwitchToSection(_("\f[c:#704a4a]Connection has been lost!\f[/c]\n\n\nPlease try it again and if the problem persists,\ncheck your network connection.")); break; case Reason::ConnectionTimedOut: mainMenu->SwitchToSection(_("\f[c:#704a4a]Cannot connect to the server!\f[/c]\n\n\nThe server is not responding for connection request.")); break; case Reason::Kicked: mainMenu->SwitchToSection(_("\f[c:#704a4a]Connection has been closed!\f[/c]\n\n\nYou have been \f[c:#907050]kicked\f[/c] off the server.\nContact server administrators for more information.")); break; @@ -779,7 +802,7 @@ void GameEventHandler::OnPacketReceived(const Peer& peer, std::uint8_t channelId packet.WriteVariableUint32(levelName.size()); packet.Write(levelName.data(), levelName.size()); - _networkManager->SendToPeer(peer, NetworkChannel::Main, packet.GetBuffer(), packet.GetSize()); + _networkManager->SendToPeer(peer, NetworkChannel::Main, packet); break; }*/ } diff --git a/Sources/Shared/Containers/Array.h b/Sources/Shared/Containers/Array.h index 60f16446..d9abdcd4 100644 --- a/Sources/Shared/Containers/Array.h +++ b/Sources/Shared/Containers/Array.h @@ -1,6 +1,7 @@ // Copyright © 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, -// 2017, 2018, 2019, 2020, 2021, 2022, 2023 +// 2017, 2018, 2019, 2020, 2021, 2022, 2023, 2024 // Vladimír Vondruš and contributors +// Copyright © 2020-2024 Dan R. // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the "Software"), diff --git a/Sources/Shared/Containers/ArrayView.h b/Sources/Shared/Containers/ArrayView.h index c01b5d2d..10afb156 100644 --- a/Sources/Shared/Containers/ArrayView.h +++ b/Sources/Shared/Containers/ArrayView.h @@ -1,6 +1,7 @@ // Copyright © 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, -// 2017, 2018, 2019, 2020, 2021, 2022, 2023 +// 2017, 2018, 2019, 2020, 2021, 2022, 2023, 2024 // Vladimír Vondruš and contributors +// Copyright © 2020-2024 Dan R. // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the "Software"), @@ -554,11 +555,26 @@ namespace Death { namespace Containers { return size_; } - /** @overload */ + /** + @brief C array size + + Equivalent to @ref std::size() from C++17. See also @ref arraySize(U(T::*)[size_]) + for querying size of an array member. + */ template constexpr std::size_t arraySize(T(&)[size_]) { return size_; } + /** + @brief C array member size + + Variant of @ref arraySize(T(&)[size_]) that works on array members. Note that + you have to form a pointer to a member with @cpp & @ce for this to work. + */ + template constexpr std::size_t arraySize(U(T::*)[size_]) { + return size_; + } + namespace Implementation { template struct StaticArrayViewConverter; diff --git a/Sources/Shared/Containers/DateTime.cpp b/Sources/Shared/Containers/DateTime.cpp index 797cf047..6744befc 100644 --- a/Sources/Shared/Containers/DateTime.cpp +++ b/Sources/Shared/Containers/DateTime.cpp @@ -1147,7 +1147,7 @@ namespace Death { namespace Containers { DateTime::Tm DateTime::Partitioned(const TimeZone tz) const { if (!IsValid()) { - return { }; + return {}; } time_t time = GetTicks(); diff --git a/Sources/Shared/Containers/GrowableArray.h b/Sources/Shared/Containers/GrowableArray.h index 6cc73edf..b345318f 100644 --- a/Sources/Shared/Containers/GrowableArray.h +++ b/Sources/Shared/Containers/GrowableArray.h @@ -1,6 +1,7 @@ // Copyright © 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, -// 2017, 2018, 2019, 2020, 2021, 2022, 2023 +// 2017, 2018, 2019, 2020, 2021, 2022, 2023, 2024 // Vladimír Vondruš and contributors +// Copyright © 2020-2024 Dan R. // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the "Software"), diff --git a/Sources/Shared/Containers/Pair.h b/Sources/Shared/Containers/Pair.h index fc67eb7d..f4597b55 100644 --- a/Sources/Shared/Containers/Pair.h +++ b/Sources/Shared/Containers/Pair.h @@ -1,7 +1,8 @@ // Copyright © 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, -// 2017, 2018, 2019, 2020, 2021, 2022, 2023 +// 2017, 2018, 2019, 2020, 2021, 2022, 2023, 2024 // Vladimír Vondruš and contributors // Copyright © 2022 Stanislaw Halik +// Copyright © 2020-2024 Dan R. // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the "Software"), diff --git a/Sources/Shared/Containers/Reference.h b/Sources/Shared/Containers/Reference.h index b8f464be..a0b57435 100644 --- a/Sources/Shared/Containers/Reference.h +++ b/Sources/Shared/Containers/Reference.h @@ -1,6 +1,7 @@ // Copyright © 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, -// 2017, 2018, 2019, 2020, 2021, 2022, 2023 +// 2017, 2018, 2019, 2020, 2021, 2022, 2023, 2024 // Vladimír Vondruš and contributors +// Copyright © 2020-2024 Dan R. // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the "Software"), diff --git a/Sources/Shared/Containers/SequenceHelpers.h b/Sources/Shared/Containers/SequenceHelpers.h index cf6f1a83..b7682887 100644 --- a/Sources/Shared/Containers/SequenceHelpers.h +++ b/Sources/Shared/Containers/SequenceHelpers.h @@ -1,6 +1,7 @@ // Copyright © 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, -// 2017, 2018, 2019, 2020, 2021, 2022, 2023 +// 2017, 2018, 2019, 2020, 2021, 2022, 2023, 2024 // Vladimír Vondruš and contributors +// Copyright © 2020-2024 Dan R. // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the "Software"), diff --git a/Sources/Shared/Containers/StaticArray.h b/Sources/Shared/Containers/StaticArray.h index 11d4f316..78262359 100644 --- a/Sources/Shared/Containers/StaticArray.h +++ b/Sources/Shared/Containers/StaticArray.h @@ -1,6 +1,7 @@ // Copyright © 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, -// 2017, 2018, 2019, 2020, 2021, 2022, 2023 +// 2017, 2018, 2019, 2020, 2021, 2022, 2023, 2024 // Vladimír Vondruš and contributors +// Copyright © 2020-2024 Dan R. // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the "Software"), @@ -22,9 +23,8 @@ #pragma once -#include "../CommonBase.h" +#include "Array.h" #include "SequenceHelpers.h" -#include "Tags.h" #include #include diff --git a/Sources/Shared/Containers/String.cpp b/Sources/Shared/Containers/String.cpp index 64e95af5..1dea30f1 100644 --- a/Sources/Shared/Containers/String.cpp +++ b/Sources/Shared/Containers/String.cpp @@ -23,7 +23,7 @@ namespace Death { namespace Containers { String String::nullTerminatedView(StringView view) { if ((view.flags() & StringViewFlags::NullTerminated) == StringViewFlags::NullTerminated) { - String out { view.data(), view.size(), [](char*, std::size_t) { } }; + String out{view.data(), view.size(), [](char*, std::size_t) {}}; out._large.size |= std::size_t(view.flags() & StringViewFlags::Global); return out; } @@ -32,7 +32,7 @@ namespace Death { namespace Containers { String String::nullTerminatedView(AllocatedInitT, StringView view) { if ((view.flags() & StringViewFlags::NullTerminated) == StringViewFlags::NullTerminated) { - String out { view.data(), view.size(), [](char*, std::size_t) { } }; + String out{view.data(), view.size(), [](char*, std::size_t) {}}; out._large.size |= std::size_t(view.flags() & StringViewFlags::Global); return out; } @@ -41,7 +41,7 @@ namespace Death { namespace Containers { String String::nullTerminatedGlobalView(StringView view) { if ((view.flags() & (StringViewFlags::NullTerminated | StringViewFlags::Global)) == (StringViewFlags::NullTerminated | StringViewFlags::Global)) { - String out { view.data(), view.size(), [](char*, std::size_t) { } }; + String out{view.data(), view.size(), [](char*, std::size_t) {}}; out._large.size |= std::size_t(StringViewFlags::Global); return out; } @@ -50,7 +50,7 @@ namespace Death { namespace Containers { String String::nullTerminatedGlobalView(AllocatedInitT, StringView view) { if ((view.flags() & (StringViewFlags::NullTerminated | StringViewFlags::Global)) == (StringViewFlags::NullTerminated | StringViewFlags::Global)) { - String out { view.data(), view.size(), [](char*, std::size_t) { } }; + String out{view.data(), view.size(), [](char*, std::size_t) {}}; out._large.size |= std::size_t(StringViewFlags::Global); return out; } diff --git a/Sources/Shared/Containers/String.h b/Sources/Shared/Containers/String.h index 93bf7cfc..60616c21 100644 --- a/Sources/Shared/Containers/String.h +++ b/Sources/Shared/Containers/String.h @@ -1,6 +1,7 @@ // Copyright © 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, -// 2017, 2018, 2019, 2020, 2021, 2022, 2023 +// 2017, 2018, 2019, 2020, 2021, 2022, 2023, 2024 // Vladimír Vondruš and contributors +// Copyright © 2020-2024 Dan R. // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the "Software"), diff --git a/Sources/Shared/Containers/StringStl.h b/Sources/Shared/Containers/StringStl.h index 74d0bddf..d5485498 100644 --- a/Sources/Shared/Containers/StringStl.h +++ b/Sources/Shared/Containers/StringStl.h @@ -1,6 +1,7 @@ // Copyright © 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, -// 2017, 2018, 2019, 2020, 2021, 2022, 2023 +// 2017, 2018, 2019, 2020, 2021, 2022, 2023, 2024 // Vladimír Vondruš and contributors +// Copyright © 2020-2024 Dan R. // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the "Software"), diff --git a/Sources/Shared/Containers/StringStlView.h b/Sources/Shared/Containers/StringStlView.h index 4c9182bc..4ac86082 100644 --- a/Sources/Shared/Containers/StringStlView.h +++ b/Sources/Shared/Containers/StringStlView.h @@ -1,6 +1,7 @@ // Copyright © 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, -// 2017, 2018, 2019, 2020, 2021, 2022, 2023 +// 2017, 2018, 2019, 2020, 2021, 2022, 2023, 2024 // Vladimír Vondruš and contributors +// Copyright © 2020-2024 Dan R. // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the "Software"), diff --git a/Sources/Shared/Containers/StringUtils.h b/Sources/Shared/Containers/StringUtils.h index a257ef9e..09345117 100644 --- a/Sources/Shared/Containers/StringUtils.h +++ b/Sources/Shared/Containers/StringUtils.h @@ -1,6 +1,7 @@ // Copyright © 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, -// 2017, 2018, 2019, 2020, 2021, 2022, 2023 +// 2017, 2018, 2019, 2020, 2021, 2022, 2023, 2024 // Vladimír Vondruš and contributors +// Copyright © 2020-2024 Dan R. // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the "Software"), diff --git a/Sources/Shared/Containers/StringView.cpp b/Sources/Shared/Containers/StringView.cpp index 19194310..da551e33 100644 --- a/Sources/Shared/Containers/StringView.cpp +++ b/Sources/Shared/Containers/StringView.cpp @@ -83,7 +83,7 @@ namespace Death { namespace Containers { } // If the substring is larger or no match was found, fail - return { }; + return {}; } } @@ -122,7 +122,7 @@ namespace Death { namespace Containers { } // If the substring is larger or no match was found, fail - return { }; + return {}; } namespace @@ -591,7 +591,7 @@ namespace Death { namespace Containers { return i + __builtin_ctz(mask); } - return { }; + return {}; }; } #endif @@ -619,7 +619,7 @@ namespace Death { namespace Containers { // `*(data - 1)` blows up, so I actually need to. if (data) for (const char* i = data + size - 1; i >= data; --i) if (*i == character) return i; - return { }; + return {}; } /* I don't want to include just for std::find_first_of() and @@ -646,7 +646,7 @@ namespace Death { namespace Containers { const char* stringFindAny(const char* const data, const std::size_t size, const char* const characters, const std::size_t characterCount) { for (const char* i = data, *end = data + size; i != end; ++i) if (std::memchr(characters, *i, characterCount)) return i; - return { }; + return {}; } // Variants of the above. Not sure if those even have any vaguely corresponding C lib API. Probably not. @@ -654,19 +654,19 @@ namespace Death { namespace Containers { const char* stringFindLastAny(const char* const data, const std::size_t size, const char* const characters, const std::size_t characterCount) { for (const char* i = data + size; i != data; --i) if (std::memchr(characters, *(i - 1), characterCount)) return i - 1; - return { }; + return {}; } const char* stringFindNotAny(const char* const data, const std::size_t size, const char* const characters, const std::size_t characterCount) { for (const char* i = data, *end = data + size; i != end; ++i) if (!std::memchr(characters, *i, characterCount)) return i; - return { }; + return {}; } const char* stringFindLastNotAny(const char* const data, const std::size_t size, const char* const characters, const std::size_t characterCount) { for (const char* i = data + size; i != data; --i) if (!std::memchr(characters, *(i - 1), characterCount)) return i - 1; - return { }; + return {}; } namespace diff --git a/Sources/Shared/Containers/Tags.h b/Sources/Shared/Containers/Tags.h index ad5065c4..14dba6f6 100644 --- a/Sources/Shared/Containers/Tags.h +++ b/Sources/Shared/Containers/Tags.h @@ -1,6 +1,7 @@ // Copyright © 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, -// 2017, 2018, 2019, 2020, 2021, 2022, 2023 +// 2017, 2018, 2019, 2020, 2021, 2022, 2023, 2024 // Vladimír Vondruš and contributors +// Copyright © 2020-2024 Dan R. // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the "Software"), diff --git a/Sources/Shared/Cpu.h b/Sources/Shared/Cpu.h index a142e530..5ae9841c 100644 --- a/Sources/Shared/Cpu.h +++ b/Sources/Shared/Cpu.h @@ -2,6 +2,7 @@ // 2017, 2018, 2019, 2020, 2021, 2022 // Vladimír Vondruš and contributors // Copyright © 2023 Robert Clausecker +// Copyright © 2020-2024 Dan R. // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the "Software"), @@ -315,9 +316,9 @@ namespace Death { namespace Cpu { namespace Implementation { - // A common type used in all tag constructors to avoid ambiguous calls when using { } + // A common type used in all tag constructors to avoid ambiguous calls when using {} struct InitT { }; - constexpr InitT Init { }; + constexpr InitT Init{}; enum: unsigned int { ExtraTagBitOffset = 16 }; } @@ -329,7 +330,7 @@ namespace Death { namespace Cpu { @see @ref tag(), @ref features() */ struct ScalarT { - // Explicit constructor to avoid ambiguous calls when using { } + // Explicit constructor to avoid ambiguous calls when using {} constexpr explicit ScalarT(Implementation::InitT) {} }; @@ -348,7 +349,7 @@ namespace Death { namespace Cpu { @see @ref tag(), @ref features() */ struct Sse2T : ScalarT { - // Explicit constructor to avoid ambiguous calls when using { } + // Explicit constructor to avoid ambiguous calls when using {} constexpr explicit Sse2T(Implementation::InitT) : ScalarT{Implementation::Init} {} }; @@ -360,7 +361,7 @@ namespace Death { namespace Cpu { @see @ref tag(), @ref features() */ struct Sse3T : Sse2T { - // Explicit constructor to avoid ambiguous calls when using { } + // Explicit constructor to avoid ambiguous calls when using {} constexpr explicit Sse3T(Implementation::InitT) : Sse2T{Implementation::Init} {} }; @@ -372,7 +373,7 @@ namespace Death { namespace Cpu { @see @ref tag(), @ref features() */ struct Ssse3T : Sse3T { - // Explicit constructor to avoid ambiguous calls when using { } + // Explicit constructor to avoid ambiguous calls when using {} constexpr explicit Ssse3T(Implementation::InitT) : Sse3T{Implementation::Init} {} }; @@ -384,7 +385,7 @@ namespace Death { namespace Cpu { @see @ref tag(), @ref features() */ struct Sse41T : Ssse3T { - // Explicit constructor to avoid ambiguous calls when using { } + // Explicit constructor to avoid ambiguous calls when using {} constexpr explicit Sse41T(Implementation::InitT) : Ssse3T{Implementation::Init} {} }; @@ -396,7 +397,7 @@ namespace Death { namespace Cpu { @see @ref tag(), @ref features() */ struct Sse42T : Sse41T { - // Explicit constructor to avoid ambiguous calls when using { } + // Explicit constructor to avoid ambiguous calls when using {} constexpr explicit Sse42T(Implementation::InitT) : Sse41T{Implementation::Init} {} }; @@ -408,7 +409,7 @@ namespace Death { namespace Cpu { @see @ref tag(), @ref features() */ struct PopcntT { - // Explicit constructor to avoid ambiguous calls when using { } + // Explicit constructor to avoid ambiguous calls when using {} constexpr explicit PopcntT(Implementation::InitT) {} }; @@ -420,7 +421,7 @@ namespace Death { namespace Cpu { @see @ref tag(), @ref features() */ struct LzcntT { - // Explicit constructor to avoid ambiguous calls when using { } + // Explicit constructor to avoid ambiguous calls when using {} constexpr explicit LzcntT(Implementation::InitT) {} }; @@ -432,7 +433,7 @@ namespace Death { namespace Cpu { @see @ref tag(), @ref features() */ struct Bmi1T { - // Explicit constructor to avoid ambiguous calls when using { } + // Explicit constructor to avoid ambiguous calls when using {} constexpr explicit Bmi1T(Implementation::InitT) {} }; @@ -443,7 +444,7 @@ namespace Death { namespace Cpu { @see @ref tag(), @ref features() */ struct Bmi2T { - // Explicit constructor to avoid ambiguous calls when using { } + // Explicit constructor to avoid ambiguous calls when using {} constexpr explicit Bmi2T(Implementation::InitT) {} }; @@ -455,7 +456,7 @@ namespace Death { namespace Cpu { @see @ref tag(), @ref features() */ struct AvxT: Sse42T { - // Explicit constructor to avoid ambiguous calls when using { } + // Explicit constructor to avoid ambiguous calls when using {} constexpr explicit AvxT(Implementation::InitT) : Sse42T{Implementation::Init} {} }; @@ -467,7 +468,7 @@ namespace Death { namespace Cpu { @see @ref tag(), @ref features() */ struct AvxF16cT { - // Explicit constructor to avoid ambiguous calls when using { } + // Explicit constructor to avoid ambiguous calls when using {} constexpr explicit AvxF16cT(Implementation::InitT) {} }; @@ -479,7 +480,7 @@ namespace Death { namespace Cpu { @see @ref tag(), @ref features() */ struct AvxFmaT { - // Explicit constructor to avoid ambiguous calls when using { } + // Explicit constructor to avoid ambiguous calls when using {} constexpr explicit AvxFmaT(Implementation::InitT) {} }; @@ -491,7 +492,7 @@ namespace Death { namespace Cpu { @see @ref tag(), @ref features() */ struct Avx2T : AvxT { - // Explicit constructor to avoid ambiguous calls when using { } + // Explicit constructor to avoid ambiguous calls when using {} constexpr explicit Avx2T(Implementation::InitT) : AvxT{Implementation::Init} {} }; @@ -503,7 +504,7 @@ namespace Death { namespace Cpu { @see @ref tag(), @ref features() */ struct Avx512fT : Avx2T { - // Explicit constructor to avoid ambiguous calls when using { } + // Explicit constructor to avoid ambiguous calls when using {} constexpr explicit Avx512fT(Implementation::InitT) : Avx2T{Implementation::Init} {} }; @@ -577,7 +578,7 @@ namespace Death { namespace Cpu { @see @ref tag(), @ref features() */ struct NeonT : ScalarT { - // Explicit constructor to avoid ambiguous calls when using { } + // Explicit constructor to avoid ambiguous calls when using {} constexpr explicit NeonT(Implementation::InitT) : ScalarT{Implementation::Init} {} }; @@ -589,7 +590,7 @@ namespace Death { namespace Cpu { @see @ref tag(), @ref features() */ struct NeonFmaT : NeonT { - // Explicit constructor to avoid ambiguous calls when using { } + // Explicit constructor to avoid ambiguous calls when using {} constexpr explicit NeonFmaT(Implementation::InitT) : NeonT{Implementation::Init} {} }; @@ -601,7 +602,7 @@ namespace Death { namespace Cpu { @see @ref tag(), @ref features() */ struct NeonFp16T : NeonFmaT { - // Explicit constructor to avoid ambiguous calls when using { } + // Explicit constructor to avoid ambiguous calls when using {} constexpr explicit NeonFp16T(Implementation::InitT) : NeonFmaT{Implementation::Init} {} }; @@ -628,7 +629,7 @@ namespace Death { namespace Cpu { @see @ref tag(), @ref features() */ struct Simd128T: ScalarT { - // Explicit constructor to avoid ambiguous calls when using { } + // Explicit constructor to avoid ambiguous calls when using {} constexpr explicit Simd128T(Implementation::InitT): ScalarT{Implementation::Init} { } }; @@ -1012,13 +1013,13 @@ namespace Death { namespace Cpu { // for TypeTraits::Index. Heh. Clang 14 warns if I don't cast because bitwise operations between // different enums are deprecated in C++20. template Priority<(static_cast(TypeTraits::Index)& ExtraTagMask ? 1 : BitIndex(TypeTraits::Index)& BaseTagMask>::Value * (ExtraTagCount + 1))> constexpr priority(T) { - return { }; + return {}; } template Priority<(BitIndex::Value* (ExtraTagCount + 1) + BitCount<((value& ExtraTagMask) >> ExtraTagBitOffset)>::Value)> constexpr priority(Tags) { static_assert(!((value & BaseTagMask) & ((value & BaseTagMask) - 1)), "more than one base tag used"); // GCC 4.8 loudly complains about enum comparison if I don't cast, sigh static_assert(((value & ExtraTagMask) >> ExtraTagBitOffset) < (1 << static_cast(ExtraTagCount)), "extra tag out of expected bounds"); - return { }; + return {}; } } @@ -2867,7 +2868,7 @@ namespace Death { namespace Cpu { unsigned int ax, bx, cx, dx; } e; int data[4]; - } cpuid { }; + } cpuid{}; Implementation::cpuid(cpuid.data, 1, 0); diff --git a/Sources/Shared/Environment.cpp b/Sources/Shared/Environment.cpp index 1367f5c8..6c4c750d 100644 --- a/Sources/Shared/Environment.cpp +++ b/Sources/Shared/Environment.cpp @@ -35,7 +35,7 @@ namespace Death { namespace Environment { { FILE* fp = ::fopen("/System/Library/CoreServices/SystemVersion.plist", "r"); if (fp == nullptr) { - return { }; + return {}; } Containers::String result; @@ -80,7 +80,7 @@ namespace Death { namespace Environment { if (fp == nullptr) { fp = ::fopen("/usr/lib/os-release", "r"); if (fp == nullptr) { - return { }; + return {}; } } diff --git a/Sources/Shared/IO/HttpRequest.h b/Sources/Shared/IO/HttpRequest.h index 1de9a198..7cc483f4 100644 --- a/Sources/Shared/IO/HttpRequest.h +++ b/Sources/Shared/IO/HttpRequest.h @@ -547,7 +547,7 @@ namespace Death { namespace IO { namespace Http { // RFC 3986, 3.1. Scheme auto i = begin; if (i == end || !IsAlphaChar(*begin)) { - return { }; + return {}; } for (; i != end && (IsAlphaChar(*i) || IsDigitChar(*i) || *i == '+' || *i == '-' || *i == '.'); ++i) { @@ -556,13 +556,13 @@ namespace Death { namespace IO { namespace Http { result.Scheme = Containers::String(begin, i - begin); if (i == end || *i++ != ':') { - return { }; + return {}; } if (i == end || *i++ != '/') { - return { }; + return {}; } if (i == end || *i++ != '/') { - return { }; + return {}; } // RFC 3986, 3.2. Authority @@ -743,7 +743,7 @@ namespace Death { namespace IO { namespace Http { auto fieldName = std::move(tokenResult.second); if (i == end || *i++ != ':') { - return { i, { } }; + return {i, {}}; } i = SkipWhiteSpaces(i, end); @@ -753,13 +753,13 @@ namespace Death { namespace IO { namespace Http { auto fieldValue = std::move(valueResult.second); if (i == end || *i++ != '\r') { - return { i, { } }; + return {i, {}}; } if (i == end || *i++ != '\n') { - return { i, { } }; + return {i, {}}; } - return { i, { std::move(fieldName), std::move(fieldValue) } }; + return {i, {std::move(fieldName), std::move(fieldValue)}}; } // RFC 7230, 3.1.2. Status Line @@ -770,24 +770,24 @@ namespace Death { namespace IO { namespace Http { auto i = httpVersionResult.first; if (i == end || *i++ != ' ') { - return { i, { } }; + return {i, {}}; } const auto statusCodeResult = ParseStatusCode(i, end); i = statusCodeResult.first; if (i == end || *i++ != ' ') { - return { i, { } }; + return {i, {}}; } auto reasonPhraseResult = ParseReasonPhrase(i, end); i = reasonPhraseResult.first; if (i == end || *i++ != '\r') { - return { i, { } }; + return {i, {}}; } if (i == end || *i++ != '\n') { - return { i, { } }; + return {i, {}}; } return { i, HttpStatus { @@ -928,7 +928,7 @@ namespace Death { namespace IO { namespace Http { return { HttpStatus::NotImplemented }; } - addrinfo hints = { }; + addrinfo hints = {}; hints.ai_family = GetAddressFamily(internetProtocol); hints.ai_socktype = SOCK_STREAM; @@ -1017,7 +1017,7 @@ namespace Death { namespace IO { namespace Http { if (fieldValue == "chunked"_s) { chunkedResponse = true; } else { - return { }; + return {}; } } else if (fieldName == "content-length"_s) { // RFC 7230, 3.3.2. Content-Length diff --git a/Sources/Shared/IO/MemoryStream.h b/Sources/Shared/IO/MemoryStream.h index 52c12b8f..0bb945f6 100644 --- a/Sources/Shared/IO/MemoryStream.h +++ b/Sources/Shared/IO/MemoryStream.h @@ -35,6 +35,10 @@ namespace Death { namespace IO { return _buffer.data(); } + DEATH_ALWAYS_INLINE const std::uint8_t* GetBuffer() const { + return _buffer.data(); + } + DEATH_ALWAYS_INLINE const std::uint8_t* GetCurrentPointer(std::int32_t bytes) { if (_seekOffset + bytes > _size) { return nullptr; diff --git a/Sources/Shared/IO/PakFile.h b/Sources/Shared/IO/PakFile.h index c362517f..46414309 100644 --- a/Sources/Shared/IO/PakFile.h +++ b/Sources/Shared/IO/PakFile.h @@ -92,7 +92,13 @@ namespace Death { namespace IO { enum class ItemFlags : std::uint32_t { None = 0, Directory = 0x01, - ZlibCompressed = 0x02 + ZlibCompressed = 0x02, + + Lz4Compressed = 0x04, // Not implemented + Lzma2Compressed = 0x08, // Not implemented + Aes256Encrypten = 0x10, // Not implemented + + Link = 0x80 // Not implemented }; DEFINE_PRIVATE_ENUM_OPERATORS(ItemFlags); diff --git a/Sources/Shared/IO/Stream.h b/Sources/Shared/IO/Stream.h index d1a819af..e7c10171 100644 --- a/Sources/Shared/IO/Stream.h +++ b/Sources/Shared/IO/Stream.h @@ -74,7 +74,7 @@ namespace Death { namespace IO { template::value>::type> DEATH_ALWAYS_INLINE T ReadValue() { - T buffer = { }; + T buffer = {}; Read(&buffer, sizeof(T)); return buffer; } diff --git a/Sources/Shared/IntrinsicsAvx.h b/Sources/Shared/IntrinsicsAvx.h index 55ae48c3..1ab55c4d 100644 --- a/Sources/Shared/IntrinsicsAvx.h +++ b/Sources/Shared/IntrinsicsAvx.h @@ -1,6 +1,7 @@ // Copyright © 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, -// 2017, 2018, 2019, 2020, 2021, 2022 +// 2017, 2018, 2019, 2020, 2021, 2022, 2023, 2024 // Vladimír Vondruš and contributors +// Copyright © 2020-2024 Dan R. // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the "Software"), diff --git a/Sources/Shared/IntrinsicsSse2.h b/Sources/Shared/IntrinsicsSse2.h index 87cef082..2278abd2 100644 --- a/Sources/Shared/IntrinsicsSse2.h +++ b/Sources/Shared/IntrinsicsSse2.h @@ -1,6 +1,7 @@ // Copyright © 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, -// 2017, 2018, 2019, 2020, 2021, 2022 +// 2017, 2018, 2019, 2020, 2021, 2022, 2023, 2024 // Vladimír Vondruš and contributors +// Copyright © 2020-2024 Dan R. // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the "Software"), diff --git a/Sources/Shared/IntrinsicsSse3.h b/Sources/Shared/IntrinsicsSse3.h index f6b932cb..903a5812 100644 --- a/Sources/Shared/IntrinsicsSse3.h +++ b/Sources/Shared/IntrinsicsSse3.h @@ -1,6 +1,7 @@ // Copyright © 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, -// 2017, 2018, 2019, 2020, 2021, 2022 +// 2017, 2018, 2019, 2020, 2021, 2022, 2023, 2024 // Vladimír Vondruš and contributors +// Copyright © 2020-2024 Dan R. // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the "Software"), diff --git a/Sources/Shared/IntrinsicsSse4.h b/Sources/Shared/IntrinsicsSse4.h index fdda9397..1d946b84 100644 --- a/Sources/Shared/IntrinsicsSse4.h +++ b/Sources/Shared/IntrinsicsSse4.h @@ -1,6 +1,7 @@ // Copyright © 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, -// 2017, 2018, 2019, 2020, 2021, 2022 +// 2017, 2018, 2019, 2020, 2021, 2022, 2023, 2024 // Vladimír Vondruš and contributors +// Copyright © 2020-2024 Dan R. // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the "Software"), diff --git a/Sources/Shared/IntrinsicsSsse3.h b/Sources/Shared/IntrinsicsSsse3.h index 859fe1d4..0f160aa0 100644 --- a/Sources/Shared/IntrinsicsSsse3.h +++ b/Sources/Shared/IntrinsicsSsse3.h @@ -1,6 +1,7 @@ // Copyright © 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, -// 2017, 2018, 2019, 2020, 2021, 2022 +// 2017, 2018, 2019, 2020, 2021, 2022, 2023, 2024 // Vladimír Vondruš and contributors +// Copyright © 2020-2024 Dan R. // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the "Software"), diff --git a/Sources/Shared/Utf8.cpp b/Sources/Shared/Utf8.cpp index 9443ce53..ce8de0b3 100644 --- a/Sources/Shared/Utf8.cpp +++ b/Sources/Shared/Utf8.cpp @@ -139,7 +139,7 @@ namespace Death { namespace Utf8 { Containers::String FromUtf16(const wchar_t* source, std::int32_t sourceSize) { - if (sourceSize == 0) return { }; + if (sourceSize == 0) return {}; // WCtoMB counts the trailing \0 into the size, which we have to cut. Containers::String takes // care of allocating extra for the null terminator so we don't need to do that explicitly. diff --git a/Sources/nCine/Application.cpp b/Sources/nCine/Application.cpp index e340e7b4..77cb2be7 100644 --- a/Sources/nCine/Application.cpp +++ b/Sources/nCine/Application.cpp @@ -348,215 +348,6 @@ namespace nCine #endif } } - - void WriteTraceEntry(TraceLevel level, std::uint64_t timestamp, StringView threadId, StringView message) - { - char logEntryWithColors[MaxLogEntryLength + 24]; - -#if defined(DEATH_TARGET_ANDROID) - std::int32_t length2 = 0; - AppendLevel(logEntryWithColors, length2, level, threadId); - AppendPart(logEntryWithColors, length2, message.data(), (std::int32_t)message.size()); - - android_LogPriority priority; - switch (level) { - case TraceLevel::Fatal: priority = ANDROID_LOG_FATAL; break; - case TraceLevel::Assert: // Android doesn't support this priority, use ANDROID_LOG_ERROR instead - case TraceLevel::Error: priority = ANDROID_LOG_ERROR; break; - case TraceLevel::Warning: priority = ANDROID_LOG_WARN; break; - case TraceLevel::Info: priority = ANDROID_LOG_INFO; break; - default: priority = ANDROID_LOG_DEBUG; break; - } - - std::int32_t result = __android_log_write(priority, NCINE_APP, logEntryWithColors); - std::int32_t n = 0; - while (result == -11 /*EAGAIN*/ && n < 2) { - ::usleep(2000); // 2ms in microseconds - result = __android_log_write(priority, NCINE_APP, logEntryWithColors); - n++; - } -#elif defined(DEATH_TARGET_SWITCH) - std::int32_t length2 = 0; - AppendLevel(logEntryWithColors, length2, level, threadId); - AppendPart(logEntryWithColors, length2, message.data(), (std::int32_t)message.size()); - svcOutputDebugString(logEntryWithColors, length2); -#elif defined(DEATH_TARGET_WINDOWS_RT) - // Use OutputDebugStringA() to avoid conversion UTF-8 => UTF-16 => current code page - std::int32_t length2 = 0; - AppendLevel(logEntryWithColors, length2, level, threadId); - AppendPart(logEntryWithColors, length2, message.data(), (std::int32_t)message.size()); - if (length2 >= MaxLogEntryLength - 2) { - length2 = MaxLogEntryLength - 2; - } - logEntryWithColors[length2++] = '\n'; - logEntryWithColors[length2] = '\0'; - ::OutputDebugStringA(logEntryWithColors); -#else -# if defined(DEATH_TARGET_WINDOWS) && defined(DEATH_DEBUG) - if (__consoleType >= ConsoleType::Redirect) { -# endif - // Colorize the output - std::int32_t length2 = 0; - std::int32_t logMsgFuncLength = 0; - AppendMessagePrefixIfAny(logEntryWithColors, length2, message.data(), logMsgFuncLength, level); - - if (__consoleType >= ConsoleType::EscapeCodes) { -# if defined(DEATH_TARGET_EMSCRIPTEN) - bool shouldResetBefore = (level != TraceLevel::Warning && level != TraceLevel::Debug); -# else - bool shouldResetBefore = true; -# endif - bool shouldResetAfter = (level == TraceLevel::Debug || level == TraceLevel::Warning || level == TraceLevel::Error || level == TraceLevel::Assert || level == TraceLevel::Fatal); - - if (level < TraceLevel::Error && __consoleType >= ConsoleType::EscapeCodes24bit) { - std::int32_t prevState = 0; - StringView message2 = StringView(message.data() + logMsgFuncLength, message.size() - logMsgFuncLength); - do { - StringView quotesBegin = message2.find('"'); - if (!quotesBegin) { - break; - } - StringView quotesEnd = message2.suffix(quotesBegin.end()).find('"'); - if (!quotesEnd) { - break; - } - - StringView prefix = message2.prefix(quotesBegin.begin()); - if (!prefix.empty()) { - AppendMessageColor(logEntryWithColors, length2, level, prevState == 2 || shouldResetBefore); - shouldResetBefore = false; - prevState = 1; - - AppendPart(logEntryWithColors, length2, prefix.data(), (std::int32_t)prefix.size()); - } - - if (prevState != 2) { - if (level == TraceLevel::Debug) { - AppendPart(logEntryWithColors, length2, ColorDimString); - } else if (__consoleDarkMode) { - AppendPart(logEntryWithColors, length2, ColorDarkString); - } else { - AppendPart(logEntryWithColors, length2, ColorLightString); - } - prevState = 2; - } - - StringView inner = message2.suffix(quotesBegin.begin()).prefix(quotesEnd.end()); - AppendPart(logEntryWithColors, length2, inner.data(), (std::int32_t)inner.size()); - - message2 = message2.suffix(quotesEnd.end()); - } while (!message2.empty()); - - if (!message2.empty()) { - AppendMessageColor(logEntryWithColors, length2, level, prevState == 2 || shouldResetBefore); - AppendPart(logEntryWithColors, length2, message2.data(), (std::int32_t)message2.size()); - } else if (prevState == 2) { - // Always reset color after quotes - shouldResetAfter = true; - } - } else { - AppendMessageColor(logEntryWithColors, length2, level, shouldResetBefore); - AppendPart(logEntryWithColors, length2, message.data() + logMsgFuncLength, (std::int32_t)message.size() - logMsgFuncLength); - } - - if (shouldResetAfter) { - AppendPart(logEntryWithColors, length2, ColorReset); - } - } else { - AppendPart(logEntryWithColors, length2, message.data() + logMsgFuncLength, (std::int32_t)message.size() - logMsgFuncLength); - } - - if (length2 >= MaxLogEntryLength - 2) { - length2 = MaxLogEntryLength - 2; - } - -# if defined(DEATH_TARGET_WINDOWS) - // Try to restore previous cursor position (this doesn't work correctly in Windows Terminal v1.19) - if (__consoleHandleOut != NULL) { - CONSOLE_SCREEN_BUFFER_INFO csbi; - if (::GetConsoleScreenBufferInfo(__consoleHandleOut, &csbi)) { - if (__consoleCursorY <= csbi.dwCursorPosition.Y) { - ::SetConsoleCursorPosition(__consoleHandleOut, { 0, __consoleCursorY }); - } - } - } - if (__consoleType >= ConsoleType::EscapeCodes && length2 < MaxLogEntryLength) { - // Console can be shared with parent process, so clear the rest of the line (using "\x1b[0K" sequence) - logEntryWithColors[length2++] = '\x1b'; - logEntryWithColors[length2++] = '['; - logEntryWithColors[length2++] = '0'; - logEntryWithColors[length2++] = 'K'; - } - - logEntryWithColors[length2++] = '\n'; - ::fwrite(logEntryWithColors, 1, length2, level == TraceLevel::Error || level == TraceLevel::Fatal ? stderr : stdout); - - // Save the last cursor position for later - if (__consoleHandleOut != NULL) { - CONSOLE_SCREEN_BUFFER_INFO csbi; - if (::GetConsoleScreenBufferInfo(__consoleHandleOut, &csbi)) { - __consoleCursorY = csbi.dwCursorPosition.Y; - } - } -# else - logEntryWithColors[length2++] = '\n'; - ::fwrite(logEntryWithColors, 1, length2, level == TraceLevel::Error || level == TraceLevel::Fatal ? stderr : stdout); -# endif - -# if defined(DEATH_TARGET_WINDOWS) && defined(DEATH_DEBUG) - } else { - // Use OutputDebugStringA() to avoid conversion UTF-8 => UTF-16 => current code page - std::int32_t length2 = 0; - AppendLevel(logEntryWithColors, length2, level, threadId); - AppendPart(logEntryWithColors, length2, message.data(), (std::int32_t)message.size()); - if (length2 >= MaxLogEntryLength - 2) { - length2 = MaxLogEntryLength - 2; - } - logEntryWithColors[length2++] = '\n'; - logEntryWithColors[length2] = '\0'; - ::OutputDebugStringA(logEntryWithColors); - } -# endif -#endif - -#if !defined(DEATH_TARGET_EMSCRIPTEN) - // Allow to attach custom target using Application::AttachTraceTarget() - if (__logFile != nullptr) { - std::int32_t length3 = 0; - AppendDateTime(logEntryWithColors, length3, timestamp); - logEntryWithColors[length3++] = ' '; - AppendLevel(logEntryWithColors, length3, level, threadId); - AppendPart(logEntryWithColors, length3, message.data(), (std::int32_t)message.size()); - logEntryWithColors[length3++] = '\n'; - - __logFile->Write(logEntryWithColors, length3); - } -#endif - -#if defined(WITH_IMGUI) - auto* debugOverlay = theApplication().debugOverlay_.get(); - if (debugOverlay != nullptr) { - std::int32_t length4 = 0; - AppendDateTime(logEntryWithColors, length4, timestamp); - - debugOverlay->log(level, logEntryWithColors, threadId, message); - } -#endif - -#if defined(WITH_TRACY) - std::uint32_t colorTracy; - switch (level) { - case TraceLevel::Fatal: colorTracy = 0xEC3E40; break; - case TraceLevel::Assert: colorTracy = 0xD651B0; break; - case TraceLevel::Error: colorTracy = 0xD85050; break; - case TraceLevel::Warning: colorTracy = 0xEBC77A; break; - case TraceLevel::Info: colorTracy = 0xD2D2D2; break; - default: colorTracy = 0x969696; break; - } - - TracyMessageC(message.data(), message.size(), colorTracy); -#endif - } } #endif @@ -581,7 +372,7 @@ namespace nCine return *screenViewport_; } - unsigned long int Application::GetFrameCount() const + std::uint32_t Application::GetFrameCount() const { return frameTimer_->GetTotalNumberFrames(); } @@ -943,7 +734,211 @@ namespace nCine #if defined(DEATH_TRACE) void Application::OnTraceReceived(TraceLevel level, std::uint64_t timestamp, StringView threadId, StringView message) { - WriteTraceEntry(level, timestamp, threadId, message); + char logEntryWithColors[MaxLogEntryLength + 24]; + +#if defined(DEATH_TARGET_ANDROID) + std::int32_t length2 = 0; + AppendLevel(logEntryWithColors, length2, level, threadId); + AppendPart(logEntryWithColors, length2, message.data(), (std::int32_t)message.size()); + + android_LogPriority priority; + switch (level) { + case TraceLevel::Fatal: priority = ANDROID_LOG_FATAL; break; + case TraceLevel::Assert: // Android doesn't support this priority, use ANDROID_LOG_ERROR instead + case TraceLevel::Error: priority = ANDROID_LOG_ERROR; break; + case TraceLevel::Warning: priority = ANDROID_LOG_WARN; break; + case TraceLevel::Info: priority = ANDROID_LOG_INFO; break; + default: priority = ANDROID_LOG_DEBUG; break; + } + + std::int32_t result = __android_log_write(priority, NCINE_APP, logEntryWithColors); + std::int32_t n = 0; + while (result == -11 /*EAGAIN*/ && n < 2) { + ::usleep(2000); // 2ms in microseconds + result = __android_log_write(priority, NCINE_APP, logEntryWithColors); + n++; + } +#elif defined(DEATH_TARGET_SWITCH) + std::int32_t length2 = 0; + AppendLevel(logEntryWithColors, length2, level, threadId); + AppendPart(logEntryWithColors, length2, message.data(), (std::int32_t)message.size()); + svcOutputDebugString(logEntryWithColors, length2); +#elif defined(DEATH_TARGET_WINDOWS_RT) + // Use OutputDebugStringA() to avoid conversion UTF-8 => UTF-16 => current code page + std::int32_t length2 = 0; + AppendLevel(logEntryWithColors, length2, level, threadId); + AppendPart(logEntryWithColors, length2, message.data(), (std::int32_t)message.size()); + if (length2 >= MaxLogEntryLength - 2) { + length2 = MaxLogEntryLength - 2; + } + logEntryWithColors[length2++] = '\n'; + logEntryWithColors[length2] = '\0'; + ::OutputDebugStringA(logEntryWithColors); +#else +# if defined(DEATH_TARGET_WINDOWS) && defined(DEATH_DEBUG) + if (__consoleType >= ConsoleType::Redirect) { +# endif + // Colorize the output + std::int32_t length2 = 0; + std::int32_t logMsgFuncLength = 0; + AppendMessagePrefixIfAny(logEntryWithColors, length2, message.data(), logMsgFuncLength, level); + + if (__consoleType >= ConsoleType::EscapeCodes) { +# if defined(DEATH_TARGET_EMSCRIPTEN) + bool shouldResetBefore = (level != TraceLevel::Warning && level != TraceLevel::Debug); +# else + bool shouldResetBefore = true; +# endif + bool shouldResetAfter = (level == TraceLevel::Debug || level == TraceLevel::Warning || level == TraceLevel::Error || level == TraceLevel::Assert || level == TraceLevel::Fatal); + + if (level < TraceLevel::Error && __consoleType >= ConsoleType::EscapeCodes24bit) { + std::int32_t prevState = 0; + StringView message2 = StringView(message.data() + logMsgFuncLength, message.size() - logMsgFuncLength); + do { + StringView quotesBegin = message2.find('"'); + if (!quotesBegin) { + break; + } + StringView quotesEnd = message2.suffix(quotesBegin.end()).find('"'); + if (!quotesEnd) { + break; + } + + StringView prefix = message2.prefix(quotesBegin.begin()); + if (!prefix.empty()) { + AppendMessageColor(logEntryWithColors, length2, level, prevState == 2 || shouldResetBefore); + shouldResetBefore = false; + prevState = 1; + + AppendPart(logEntryWithColors, length2, prefix.data(), (std::int32_t)prefix.size()); + } + + if (prevState != 2) { + if (level == TraceLevel::Debug) { + AppendPart(logEntryWithColors, length2, ColorDimString); + } else if (__consoleDarkMode) { + AppendPart(logEntryWithColors, length2, ColorDarkString); + } else { + AppendPart(logEntryWithColors, length2, ColorLightString); + } + prevState = 2; + } + + StringView inner = message2.suffix(quotesBegin.begin()).prefix(quotesEnd.end()); + AppendPart(logEntryWithColors, length2, inner.data(), (std::int32_t)inner.size()); + + message2 = message2.suffix(quotesEnd.end()); + } while (!message2.empty()); + + if (!message2.empty()) { + AppendMessageColor(logEntryWithColors, length2, level, prevState == 2 || shouldResetBefore); + AppendPart(logEntryWithColors, length2, message2.data(), (std::int32_t)message2.size()); + } else if (prevState == 2) { + // Always reset color after quotes + shouldResetAfter = true; + } + } else { + AppendMessageColor(logEntryWithColors, length2, level, shouldResetBefore); + AppendPart(logEntryWithColors, length2, message.data() + logMsgFuncLength, (std::int32_t)message.size() - logMsgFuncLength); + } + + if (shouldResetAfter) { + AppendPart(logEntryWithColors, length2, ColorReset); + } + } else { + AppendPart(logEntryWithColors, length2, message.data() + logMsgFuncLength, (std::int32_t)message.size() - logMsgFuncLength); + } + + if (length2 >= MaxLogEntryLength - 2) { + length2 = MaxLogEntryLength - 2; + } + +# if defined(DEATH_TARGET_WINDOWS) + // Try to restore previous cursor position (this doesn't work correctly in Windows Terminal v1.19) + if (__consoleHandleOut != NULL) { + CONSOLE_SCREEN_BUFFER_INFO csbi; + if (::GetConsoleScreenBufferInfo(__consoleHandleOut, &csbi)) { + if (__consoleCursorY <= csbi.dwCursorPosition.Y) { + ::SetConsoleCursorPosition(__consoleHandleOut, { 0, __consoleCursorY }); + } + } + } + if (__consoleType >= ConsoleType::EscapeCodes && length2 < MaxLogEntryLength) { + // Console can be shared with parent process, so clear the rest of the line (using "\x1b[0K" sequence) + logEntryWithColors[length2++] = '\x1b'; + logEntryWithColors[length2++] = '['; + logEntryWithColors[length2++] = '0'; + logEntryWithColors[length2++] = 'K'; + } + + logEntryWithColors[length2++] = '\n'; + ::fwrite(logEntryWithColors, 1, length2, level == TraceLevel::Error || level == TraceLevel::Fatal ? stderr : stdout); + + // Save the last cursor position for later + if (__consoleHandleOut != NULL) { + CONSOLE_SCREEN_BUFFER_INFO csbi; + if (::GetConsoleScreenBufferInfo(__consoleHandleOut, &csbi)) { + __consoleCursorY = csbi.dwCursorPosition.Y; + } + } +# else + logEntryWithColors[length2++] = '\n'; + ::fwrite(logEntryWithColors, 1, length2, level == TraceLevel::Error || level == TraceLevel::Fatal ? stderr : stdout); +# endif + +# if defined(DEATH_TARGET_WINDOWS) && defined(DEATH_DEBUG) + } else { + // Use OutputDebugStringA() to avoid conversion UTF-8 => UTF-16 => current code page + std::int32_t length2 = 0; + AppendLevel(logEntryWithColors, length2, level, threadId); + AppendPart(logEntryWithColors, length2, message.data(), (std::int32_t)message.size()); + if (length2 >= MaxLogEntryLength - 2) { + length2 = MaxLogEntryLength - 2; + } + logEntryWithColors[length2++] = '\n'; + logEntryWithColors[length2] = '\0'; + ::OutputDebugStringA(logEntryWithColors); + } +# endif +#endif + +#if !defined(DEATH_TARGET_EMSCRIPTEN) + // Allow to attach custom target using Application::AttachTraceTarget() + if (__logFile != nullptr) { + std::int32_t length3 = 0; + AppendDateTime(logEntryWithColors, length3, timestamp); + logEntryWithColors[length3++] = ' '; + AppendLevel(logEntryWithColors, length3, level, threadId); + AppendPart(logEntryWithColors, length3, message.data(), (std::int32_t)message.size()); + logEntryWithColors[length3++] = '\n'; + + __logFile->Write(logEntryWithColors, length3); + } +#endif + +#if defined(WITH_IMGUI) + auto* debugOverlay = theApplication().debugOverlay_.get(); + if (debugOverlay != nullptr) { + std::int32_t length4 = 0; + AppendDateTime(logEntryWithColors, length4, timestamp); + + debugOverlay->log(level, logEntryWithColors, threadId, message); + } +#endif + +#if defined(WITH_TRACY) + std::uint32_t colorTracy; + switch (level) { + case TraceLevel::Fatal: colorTracy = 0xEC3E40; break; + case TraceLevel::Assert: colorTracy = 0xD651B0; break; + case TraceLevel::Error: colorTracy = 0xD85050; break; + case TraceLevel::Warning: colorTracy = 0xEBC77A; break; + case TraceLevel::Info: colorTracy = 0xD2D2D2; break; + default: colorTracy = 0x969696; break; + } + + TracyMessageC(message.data(), message.size(), colorTracy); +#endif } void Application::OnTraceFlushed() diff --git a/Sources/nCine/Application.h b/Sources/nCine/Application.h index cd61e6b6..ec434d20 100644 --- a/Sources/nCine/Application.h +++ b/Sources/nCine/Application.h @@ -117,7 +117,7 @@ namespace nCine inline IInputManager& GetInputManager() { return *inputManager_; } /** @brief Returns the total number of frames already rendered */ - unsigned long int GetFrameCount() const; + std::uint32_t GetFrameCount() const; /** @brief Returns a factor that represents how long the last frame took relative to the desired frame time */ float GetTimeMult() const; /** @brief Returns the frame timer interface */ diff --git a/Sources/nCine/Graphics/IDebugOverlay.h b/Sources/nCine/Graphics/IDebugOverlay.h index ff1dcdcf..cdb7309a 100644 --- a/Sources/nCine/Graphics/IDebugOverlay.h +++ b/Sources/nCine/Graphics/IDebugOverlay.h @@ -35,7 +35,7 @@ namespace nCine virtual void updateFrameTimings() = 0; #if defined(DEATH_TRACE) - virtual void log(TraceLevel level, StringView time, std::uint32_t threadId, StringView message) = 0; + virtual void log(TraceLevel level, StringView time, StringView threadId, StringView message) = 0; #endif protected: @@ -43,9 +43,7 @@ namespace nCine TimeStamp lastUpdateTime_; float updateTime_; - /// Deleted copy constructor IDebugOverlay(const IDebugOverlay&) = delete; - /// Deleted assignment operator IDebugOverlay& operator=(const IDebugOverlay&) = delete; }; diff --git a/Sources/nCine/Graphics/ImGuiDebugOverlay.cpp b/Sources/nCine/Graphics/ImGuiDebugOverlay.cpp index 6d6dfa62..209148f7 100644 --- a/Sources/nCine/Graphics/ImGuiDebugOverlay.cpp +++ b/Sources/nCine/Graphics/ImGuiDebugOverlay.cpp @@ -220,7 +220,7 @@ namespace nCine } #if defined(DEATH_TRACE) - void ImGuiDebugOverlay::log(TraceLevel level, StringView time, std::uint32_t threadId, StringView message) + void ImGuiDebugOverlay::log(TraceLevel level, StringView time, StringView threadId, StringView message) { logBuffer_.emplace_back(LogMessage{time, message, threadId, level}); } @@ -501,7 +501,7 @@ namespace nCine ImGui::TextUnformatted(message.Time.begin(), message.Time.end()); ImGui::TableSetColumnIndex(1); - ImGui::Text("%i", message.ThreadId); + ImGui::TextUnformatted(message.ThreadId.begin(), message.ThreadId.end()); ImGui::TableSetColumnIndex(2); diff --git a/Sources/nCine/Graphics/ImGuiDebugOverlay.h b/Sources/nCine/Graphics/ImGuiDebugOverlay.h index 2144c6a4..e0343174 100644 --- a/Sources/nCine/Graphics/ImGuiDebugOverlay.h +++ b/Sources/nCine/Graphics/ImGuiDebugOverlay.h @@ -31,7 +31,7 @@ namespace nCine void updateFrameTimings() override; #if defined(DEATH_TRACE) - void log(TraceLevel level, StringView time, std::uint32_t threadId, StringView message) override; + void log(TraceLevel level, StringView time, StringView threadId, StringView message) override; #endif private: @@ -76,7 +76,7 @@ namespace nCine { String Time; String Text; - std::uint32_t ThreadId; + String ThreadId; TraceLevel Level; };