mirror of
https://github.com/isledecomp/isle-portable.git
synced 2026-05-01 18:13:57 +00:00
Disable third person camera and hide remote players in Isle overlay areas
Overlay areas (elevator rides, observatory, gas station/police doorways) stay within the Isle world but use fixed cameras with no free-roaming movement. The third person camera and player display were incorrectly staying active in these areas, and remote players remained visible at their last open-world position. Query GameState::m_currentArea at runtime to detect restricted areas, avoiding new state variables or hooks into decompiled code. Extract shared IsRestrictedArea() into a common header used by both the camera controller and multiplayer networking. On the multiplayer side, broadcast WORLD_NOT_VISIBLE as the worldId so remote clients hide the player via existing visibility logic, and exclude the local player from the player count when in a restricted area. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
13f6239808
commit
aa48001eb3
34
extensions/include/extensions/common/arearestriction.h
Normal file
34
extensions/include/extensions/common/arearestriction.h
Normal file
@ -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
|
||||
@ -95,6 +95,7 @@ class Controller {
|
||||
static constexpr float MIN_DISTANCE = OrbitCamera::MIN_DISTANCE;
|
||||
|
||||
private:
|
||||
void Deactivate();
|
||||
void ReinitForCharacter();
|
||||
|
||||
OrbitCamera m_orbit;
|
||||
|
||||
@ -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 <typename T>
|
||||
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<LegoActor*>(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<LegoActor*>(userActor)->GetActorId())) {
|
||||
count = 1;
|
||||
}
|
||||
else if (IsValidActorId(GameState()->GetActorId())) {
|
||||
count = 1;
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& [peerId, player] : m_remotePlayers) {
|
||||
|
||||
@ -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)
|
||||
{
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user