pawn-lang / sa-mp-fixes

Includes and plugins to fix various issues in the SA:MP server that can be fixed externally, leaving the devs time for other things.
137 stars 57 forks source link

Players colliding with each other in mod shops #53

Open IstuntmanI opened 7 years ago

IstuntmanI commented 7 years ago

Players are colliding with each other when they are in mod shops.

Temporarily change player's virtual world to playerid+1 when entering a mod shop and set it back to the old one when they leave. This helps a lot: http://wiki.sa-mp.com/wiki/OnEnterExitModShop . Additionally, we should provide a IsPlayerInModShop.

new gFIXES_PlayerInfo[ MAX_PLAYERS ][ gFIXES_PlayerInfoEnum ];

/ < resetting gFIXES_PlayerInfo[ i ][ _FIXES_inModShop ] under OnPlayerConnect > /

public OnEnterExitModShop( playerid, enterexit, interiorid ) { if( _FIXES_inModShop == enterexit ) // already has that mod shop status, probably hacking ? { Kick( playerid ); return 1; }

if( enterexit ) // Entered
{
    new lVehicleID = GetPlayerVehicleID( playerid ),
        lWorld = GetPlayerVirtualWorld( playerid );

    gFIXES_PlayerInfo[ playerid ][ _FIXES_oldVehicle ] = lVehicleID;

    SetVehicleVirtualWorld( lVehicleID, playerid + 1 );

    _FIXES_FOREACH( FIXES_gsPlayersIterator, i )
    {
        if( GetPlayerVehicleID( i ) != lVehicleID )
            continue;

        gFIXES_PlayerInfo[ i ][ _FIXES_inModShop ] = true;
        gFIXES_PlayerInfo[ i ][ _FIXES_oldWorld ] = lWorld;

        SetPlayerVirtualWorld( i, playerid + 1 );
    }

    return 1;
}

// Left
new lVehicleID = gFIXES_PlayerInfo[ playerid ][ _FIXES_oldVehicle ];

_FIXES_FOREACH( FIXES_gsPlayersIterator, i )
{
    if( GetPlayerVehicleID( i ) != lVehicleID )
        continue;

    gFIXES_PlayerInfo[ i ][ _FIXES_inModShop ] = false;
    SetPlayerVirtualWorld( i, gFIXES_PlayerInfo[ i ][ _FIXES_oldWorld ] );
}

SetVehicleVirtualWorld( lVehicleID, gFIXES_PlayerInfo[ playerid ][ _FIXES_oldWorld ] );
return 1;

}

stock bool:IsPlayerInModShop( playerid ) { if( !_FIXES_IN_RANGE( playerid, 0, MAX_PLAYERS ) ) return 0;

return gFIXES_PlayerInfo[ playerid ][ _FIXES_inModShop ];

}



I think that we should store the vehicle ID with which he entered because on servers they may abuse commands and somehow leave, but they can still press enter and leave the mod shop then, "officially" - so the ```IsPlayerInModShop``` command may help scripters to block the player to execute commands.
ziggi commented 7 years ago

You forgot about passengers.

IstuntmanI commented 7 years ago

It looks like I always forget about passengers. 😆 Thanks. I wasn't sure if OnEnterExitModShop is called for passengers too, so I searched for "OnEnterExitModShop passengers" and I see that someone already tried to solve this issue: http://forum.sa-mp.com/showthread.php?t=520391 . From that it looks like it isn't called for passengers. Edited the possible implementation in the OP.

WoutProvost commented 7 years ago

Temporarily change player's virtual world to playerid+1

Say I have a mode that is divided into different submodes with each a different virtual world assigned, and by just using GetPlayerVirtualWorld you know what submode a player is in. There are no other variables that keep track of what submode a player is in.

Within your solution, the possible virtual worlds for modshops range from 1 to 1000. Given this, say a submode uses one of the virtual worlds in that range. This could potentially break the user's script when GetPlayerVirtualWorld is used to know what submode a user is in while he is in the modshop.

To fix this, either the user could update his script, which is ... not optimal, since this include is meant to fix things, not introduce new bugs when any breaking effects are known in advance, of which this example is one. Or you could provide a starting value which the user can redefine before including the include and otherwise use the default behaviour. Which is better than the former, but still not optimal, since the user has to know of the default behaviour of this fix, or have the starting value redefined.

//myscript.pwn
#define SOME_STARTING_VW    1000
#include <fixes>

//fixes.inc
#if !defined SOME_STARTING_VW
    #define SOME_STARTING_VW    0
#endif
SetPlayerVirtualWorld(i, SOME_STARTING_VW + playerid);
Y-Less commented 7 years ago

There are over 2 milliard virtual worlds, I'm sure we can find an addition that doesn't conflict, and even hook SetPlayerVirtualWorld to give a warning if it uses a reserved one. I like playerid + 0x73654C59.

WoutProvost commented 7 years ago

Then maybe use VWs somewhere in the back, instead of in the front, since those are a lot less likely to be used already. I also like the idea about the hook and warning.

Y-Less commented 7 years ago

What I said is pretty near the back, and quite random really - nothing close to a neat number, so unlikely to have been taken. People tend to favour numbers like 1000 not 1936018521.

rt-2 commented 7 years ago

Why wouldn't we just refuse the player updates when they are in modshops? so they wont stream to each other and wont collide?

ziggi commented 7 years ago

Why wouldn't we just refuse the player updates when they are in modshops? so they wont stream to each other and wont collide?

Because other players will see players in garage.