diff --git a/extensions/include/extensions/common/arearestriction.h b/extensions/include/extensions/common/arearestriction.h new file mode 100644 index 00000000..d2104034 --- /dev/null +++ b/extensions/include/extensions/common/arearestriction.h @@ -0,0 +1,34 @@ +#pragma once + +#include "legogamestate.h" + +namespace Extensions +{ +namespace Common +{ + +// Broadcast world ID indicating the player is not visible in any world. +static constexpr int8_t WORLD_NOT_VISIBLE = -1; + +// Overlay areas within the Isle world (e_act1) that use fixed camera angles +// and have no free-roaming player movement. The player character should not +// be visible (locally or to remote peers) in these areas. +inline bool IsRestrictedArea(LegoGameState::Area p_area) +{ + switch (p_area) { + case LegoGameState::e_elevride: + case LegoGameState::e_elevride2: + case LegoGameState::e_elevopen: + case LegoGameState::e_seaview: + case LegoGameState::e_observe: + case LegoGameState::e_elevdown: + case LegoGameState::e_garadoor: + case LegoGameState::e_polidoor: + return true; + default: + return false; + } +} + +} // namespace Common +} // namespace Extensions diff --git a/extensions/include/extensions/thirdpersoncamera/controller.h b/extensions/include/extensions/thirdpersoncamera/controller.h index ae145a93..a1901160 100644 --- a/extensions/include/extensions/thirdpersoncamera/controller.h +++ b/extensions/include/extensions/thirdpersoncamera/controller.h @@ -95,6 +95,7 @@ class Controller { static constexpr float MIN_DISTANCE = OrbitCamera::MIN_DISTANCE; private: + void Deactivate(); void ReinitForCharacter(); OrbitCamera m_orbit; diff --git a/extensions/src/multiplayer/networkmanager.cpp b/extensions/src/multiplayer/networkmanager.cpp index d806cf0a..75c2d5a2 100644 --- a/extensions/src/multiplayer/networkmanager.cpp +++ b/extensions/src/multiplayer/networkmanager.cpp @@ -1,6 +1,7 @@ #include "extensions/multiplayer/networkmanager.h" #include "extensions/common/animdata.h" +#include "extensions/common/arearestriction.h" #include "extensions/common/charactercustomizer.h" #include "extensions/multiplayer/namebubblerenderer.h" #include "extensions/thirdpersoncamera.h" @@ -26,6 +27,8 @@ using namespace Extensions; using namespace Multiplayer; using Common::DetectVehicleType; using Common::IsMultiPartEmote; +using Common::IsRestrictedArea; +using Common::WORLD_NOT_VISIBLE; template void NetworkManager::SendMessage(const T& p_msg) @@ -407,7 +410,8 @@ void NetworkManager::BroadcastLocalState() PlayerStateMsg msg{}; msg.header = {MSG_STATE, m_localPeerId, m_sequence++, TARGET_BROADCAST}; msg.actorId = actorId; - msg.worldId = (int8_t) currentWorld->GetWorldId(); + msg.worldId = + IsRestrictedArea(GameState()->m_currentArea) ? WORLD_NOT_VISIBLE : (int8_t) currentWorld->GetWorldId(); msg.vehicleType = DetectVehicleType(userActor); SDL_memcpy(msg.position, pos, sizeof(msg.position)); SDL_memcpy(msg.direction, dir, sizeof(msg.direction)); @@ -714,17 +718,16 @@ void NetworkManager::NotifyPlayerCountChanged() if (m_inIsleWorld) { count = 0; - // Only count the local player if they have a valid actor. - // UserActor() can be temporarily NULL during world transitions - // (e.g. returning from a race, where LegoRace stashes the actor - // and only restores it in its destructor). Fall back to the - // GameState actorId which is restored earlier. - LegoPathActor* userActor = UserActor(); - if (userActor && IsValidActorId(static_cast(userActor)->GetActorId())) { - count = 1; - } - else if (IsValidActorId(GameState()->GetActorId())) { - count = 1; + // Only count the local player if they have a valid actor and + // are not in a restricted overlay area (elevator, observatory, etc.). + if (!IsRestrictedArea(GameState()->m_currentArea)) { + LegoPathActor* userActor = UserActor(); + if (userActor && IsValidActorId(static_cast(userActor)->GetActorId())) { + count = 1; + } + else if (IsValidActorId(GameState()->GetActorId())) { + count = 1; + } } for (auto& [peerId, player] : m_remotePlayers) { diff --git a/extensions/src/multiplayer/remoteplayer.cpp b/extensions/src/multiplayer/remoteplayer.cpp index 23f616de..59e5944a 100644 --- a/extensions/src/multiplayer/remoteplayer.cpp +++ b/extensions/src/multiplayer/remoteplayer.cpp @@ -1,6 +1,7 @@ #include "extensions/multiplayer/remoteplayer.h" #include "3dmanager/lego3dmanager.h" +#include "extensions/common/arearestriction.h" #include "extensions/common/charactercloner.h" #include "extensions/common/charactercustomizer.h" #include "extensions/multiplayer/namebubblerenderer.h" @@ -23,11 +24,12 @@ using Common::g_idleAnimCount; using Common::g_vehicleROINames; using Common::g_walkAnimCount; using Common::IsLargeVehicle; +using Common::WORLD_NOT_VISIBLE; RemotePlayer::RemotePlayer(uint32_t p_peerId, uint8_t p_actorId, uint8_t p_displayActorIndex) : m_peerId(p_peerId), m_actorId(p_actorId), m_displayActorIndex(p_displayActorIndex), m_roi(nullptr), - m_spawned(false), m_visible(false), m_targetSpeed(0.0f), m_targetVehicleType(VEHICLE_NONE), m_targetWorldId(-1), - m_lastUpdateTime(SDL_GetTicks()), m_hasReceivedUpdate(false), + m_spawned(false), m_visible(false), m_targetSpeed(0.0f), m_targetVehicleType(VEHICLE_NONE), + m_targetWorldId(WORLD_NOT_VISIBLE), m_lastUpdateTime(SDL_GetTicks()), m_hasReceivedUpdate(false), m_animator(Common::CharacterAnimatorConfig{/*.saveEmoteTransform=*/false, /*.propSuffix=*/p_peerId}), m_vehicleROI(nullptr), m_nameBubble(nullptr), m_allowRemoteCustomize(true) { diff --git a/extensions/src/thirdpersoncamera.cpp b/extensions/src/thirdpersoncamera.cpp index d789512e..cfb926c6 100644 --- a/extensions/src/thirdpersoncamera.cpp +++ b/extensions/src/thirdpersoncamera.cpp @@ -1,5 +1,6 @@ #include "extensions/thirdpersoncamera.h" +#include "extensions/common/arearestriction.h" #include "extensions/common/charactercustomizer.h" #include "extensions/thirdpersoncamera/controller.h" #include "islepathactor.h" @@ -112,7 +113,7 @@ void ThirdPersonCameraExt::HandleCamAnimEnd(LegoPathActor* p_actor) void ThirdPersonCameraExt::OnSDLEvent(SDL_Event* p_event) { - if (!s_camera || !s_inIsleWorld) { + if (!s_camera || !s_inIsleWorld || IsRestrictedArea(GameState()->m_currentArea)) { return; } diff --git a/extensions/src/thirdpersoncamera/controller.cpp b/extensions/src/thirdpersoncamera/controller.cpp index b20ddec6..a6ef51b7 100644 --- a/extensions/src/thirdpersoncamera/controller.cpp +++ b/extensions/src/thirdpersoncamera/controller.cpp @@ -3,6 +3,7 @@ #include "3dmanager/lego3dmanager.h" #include "anim/legoanim.h" #include "extensions/common/animutils.h" +#include "extensions/common/arearestriction.h" #include "extensions/common/charactercustomizer.h" #include "extensions/common/constants.h" #include "islepathactor.h" @@ -42,11 +43,17 @@ void Controller::Enable() void Controller::Disable(bool p_preserveTouch) { m_enabled = false; + Deactivate(); + if (!p_preserveTouch) { + m_input.ResetTouchState(); + } +} +void Controller::Deactivate() +{ if (m_active && m_playerROI) { m_playerROI->SetVisibility(FALSE); VideoManager()->Get3DManager()->Remove(*m_playerROI); - m_orbit.RestoreFirstPersonCamera(); } @@ -58,11 +65,7 @@ void Controller::Disable(bool p_preserveTouch) m_playerROI = nullptr; m_animator.ClearRideAnimation(); m_animator.ClearAll(); - m_orbit.ResetOrbitState(); - if (!p_preserveTouch) { - m_input.ResetTouchState(); - } } void Controller::OnActorEnter(IslePathActor* p_actor) @@ -74,7 +77,7 @@ void Controller::OnActorEnter(IslePathActor* p_actor) m_animator.SetCurrentVehicleType(DetectVehicleType(userActor)); - if (!m_enabled) { + if (!m_enabled || IsRestrictedArea(GameState()->m_currentArea)) { return; } @@ -164,6 +167,10 @@ void Controller::OnCamAnimEnd(LegoPathActor* p_actor) void Controller::Tick(float p_deltaTime) { + if (IsRestrictedArea(GameState()->m_currentArea)) { + return; + } + if (!m_display.IsDisplayActorFrozen()) { LegoPathActor* userActor = UserActor(); if (userActor) { @@ -312,6 +319,12 @@ void Controller::OnWorldEnabled(LegoWorld* p_world) return; } + if (IsRestrictedArea(GameState()->m_currentArea)) { + Deactivate(); + m_input.ResetTouchState(); + return; + } + m_animator.ClearAll(); m_orbit.ResetOrbitState(); @@ -363,6 +376,11 @@ void Controller::HandleSDLEventImpl(SDL_Event* p_event) void Controller::ReinitForCharacter() { + if (IsRestrictedArea(GameState()->m_currentArea)) { + m_active = false; + return; + } + LegoPathActor* userActor = UserActor(); if (!userActor) { m_active = false;