Alright so I tested your code and it is not working. As soon as there is more than 1 player per team, the jointeam command is called twice (as expected by your code logic) and then, is not called again since the game itself is preventing the clients to spam that command. Anyways, forcing players to execute that command is probably the worst way to change their team. So yeah, I then tried the following code.
Syntax: Select all
from events import Event
from filters.players import PlayerIter
from players.entity import PlayerEntity
from players.helpers import index_from_playerinfo
@Event
def round_end(game_event):
for player in map(PlayerEntity, PlayerIter()):
if player.team not in (2, 3):
continue
player.switch_team(5 - player.team)
And faced ton of weird issues (player not respawning or spawning with no weapon in hand but still attacking, etc.) so indvestigated why and PlayerEntity.switch_team is not calling the function it should. Currently, it calls CBasePlayer::ChangeTeam.
Syntax: Select all
//================================================================================
// TEAM HANDLING
//================================================================================
//-----------------------------------------------------------------------------
// Purpose: Put the player in the specified team
//-----------------------------------------------------------------------------
void CBasePlayer::ChangeTeam( int iTeamNum, bool bAutoTeam, bool bSilent)
{
if ( !GetGlobalTeam( iTeamNum ) )
{
Warning( "CBasePlayer::ChangeTeam( %d ) - invalid team index.\n", iTeamNum );
return;
}
// if this is our current team, just abort
if ( iTeamNum == GetTeamNumber() )
{
return;
}
// Immediately tell all clients that he's changing team. This has to be done
// first, so that all user messages that follow as a result of the team change
// come after this one, allowing the client to be prepared for them.
IGameEvent * event = gameeventmanager->CreateEvent( "player_team" );
if ( event )
{
event->SetInt("userid", GetUserID() );
event->SetInt("team", iTeamNum );
event->SetInt("oldteam", GetTeamNumber() );
event->SetInt("disconnect", IsDisconnecting());
event->SetInt("autoteam", bAutoTeam );
event->SetInt("silent", bSilent );
if ( GetTeamNumber() == TEAM_UNASSIGNED )
{
event->SetString( "name", GetPlayerName() );
}
else
{
event->SetString( "name", "" ); // don't bother sending the name except on the first connect
}
event->SetBool("isbot", !IsNetClient());
gameeventmanager->FireEvent( event );
}
// Remove him from his current team
if ( GetTeam() )
{
GetTeam()->RemovePlayer( this );
}
// Are we being added to a team?
if ( iTeamNum )
{
GetGlobalTeam( iTeamNum )->AddPlayer( this );
}
BaseClass::ChangeTeam( iTeamNum );
}
As you can see, it does nothing else than, calling the player_team event with the given parameter, updating the cs_player_manager entities adding/removing the player and then setting m_iTeamNum by calling CBaseEntity::ChangeTeam. However, it requires more work than that to actually change a player team which is done by CCSPlayer::SwitchTeam. Once I updated the signature/symbol to the following:
Syntax: Select all
# CCSPlayer::SwitchTeam
[switch_team]
binary = csgo/bin/server
identifier_windows = " 55 8B EC 83 EC 10 53 56 8B 75 08 57 8B F9 85 F6 0F"
identifier_linux = _ZN9CCSPlayer10SwitchTeamEi
arguments = POINTER,INT
return_type = VOID
convention = THISCALL
srv_check = false
The code above worked just fine. All players are switched and the timeleft is never affected.