OldUnreal / UnrealTournamentPatches

Other
967 stars 29 forks source link

[469] When spawning into a WaterZone using DeathMatchPlus and its subclasses upon loading the level, you cannot swim up or down #1348

Open RoninMastaFX opened 1 year ago

RoninMastaFX commented 1 year ago

Taken from my conversation from Xaleros and I on Discord:

Xaleros: so i just found a bug that only exists with UT Xaleros: both 436 and 469 Xaleros: if you spawn in a waterzone when the map starts Xaleros: you cannot swim up or down Xaleros: you have to die first Xaleros: if i change the gamemode to UnrealGameInfo instead of DeathMatchPlus Xaleros: then i can swim up and down Xaleros: i actually wonder if fixing this is possible without breaking compatibility Xaleros: because the funny part? Xaleros: if the gamemode of the map is forced to UnrealGameInfo Xaleros: the bug doesn't occur Xaleros: if i leave the gamemode as standard DeathMatchPlus Xaleros: the bug does occur Xaleros: which means it has to be a bug in unrealscript source

If this bug report already exists, my apologies! My quick search proved futile (in that case).

SeriousBuggie commented 1 year ago

Test map: WaterZoneCube.zip

This happen because your Physics is PHYS_Falling.

SeriousBuggie commented 1 year ago

On DeathMatchPlus player start in PlayerWaiting state, which on respawn goes to PlayerWalking, as default state. PlayerPawn.PlayerWalking.BeginState set physics: if (Physics != PHYS_Falling) SetPhysics(PHYS_Walking); PHYS_Walking if not found any base below foot, switch physics to PHYS_Falling.

When player start UnrealGameInfo, respawn come instant, without use PlayerWaiting state. it call Pawn.ClientRestart:

function ClientReStart()
{
    //log("client restart");
    Velocity = vect(0,0,0);
    Acceleration = vect(0,0,0);
    BaseEyeHeight = Default.BaseEyeHeight;
    EyeHeight = BaseEyeHeight;
    PlayWaiting();

    if ( Region.Zone.bWaterZone && (PlayerRestartState == 'PlayerWalking') )
    {
        if (HeadRegion.Zone.bWaterZone)
                PainTime = UnderWaterTime;
        setPhysics(PHYS_Swimming);
        GotoState('PlayerSwimming');
    }
    else
        GotoState(PlayerReStartState);
}

There check Player Zone, and state + physics set to proper one.

Same code called during use DeathMatchPlus, but since PlayerRestartState here is not PlayerWalking, Player just goes to PlayerRestartState, which be PlayerWaiting.

PlayerRestartState changed in DeathMatchPlus.Login:

        if ( (bGameEnded || (bRequireReady && (CountDown > 0))) && !NewPlayer.IsA('Spectator') )
            NewPlayer.PlayerRestartState = 'PlayerWaiting';
        else
            NewPlayer.PlayerRestartState = NewPlayer.Default.PlayerRestartState;

Later on DeathMatchPlus.StartMatch:

                P.PlayerRestartState = P.Default.PlayerRestartState;
                P.GotoState(P.Default.PlayerRestartState);
                if ( !P.IsA('Commander') )
                {
                    if ( !RestartPlayer(P) )
                        P.GotoState('Dying'); //failed to restart player, so let him try to respawn again
                }

into RestartPlayer can be added check for WaterZone, like on ClientRestart above.

function bool RestartPlayer( pawn aPlayer ) 
{
    local Bot B;
    local bool bResult;

    aPlayer.DamageScaling = aPlayer.Default.DamageScaling;
    B = Bot(aPlayer);
    if ( (B != None) 
        && (Level.NetMode != NM_Standalone) 
        && TooManyBots() )
    {
        aPlayer.Destroy();
        return false;
    }
    bResult = Super.RestartPlayer(aPlayer);
    if ( aPlayer.IsA('TournamentPlayer') )
        TournamentPlayer(aPlayer).StartSpot = LastStartSpot;
    return bResult;
}

But this need widely test for not break custom mods.