//AddPlayer adds the given player to lobby, If the player occupies a slot in the lobby already, switch slots. //If the player is in another lobby, removes them from that lobby before adding them. func (lobby *Lobby) AddPlayer(p *player.Player, slot int, password string) error { /* Possible errors while joining * Slot has been filled * Player has already joined a lobby * anything else? */ //Check if player is banned if lobby.IsPlayerBanned(p) { return ErrLobbyBan } if slot >= 2*format.NumberOfClassesMap[lobby.Type] || slot < 0 { return ErrBadSlot } isSubstitution := lobby.SlotNeedsSubstitute(slot) //Check whether the slot is occupied if !isSubstitution && lobby.IsSlotOccupied(slot) { return ErrFilled } if lobby.HasSlotRequirement(slot) { //check if player fits the requirements for the slot if ok, err := lobby.FitsRequirements(p, slot); !ok { return err } req, _ := lobby.GetSlotRequirement(slot) if password != req.Password { return ErrInvalidPassword } } var slotChange bool //Check if the player is currently in another lobby if currLobbyID, err := p.GetLobbyID(false); err == nil { if currLobbyID != lobby.ID { //if the player is in a different lobby, remove them from that lobby //plus substitute them curLobby, _ := GetLobbyByID(currLobbyID) if curLobby.State == InProgress { curLobby.Substitute(p) } else { curLobby.Lock() db.DB.Where("player_id = ? AND lobby_id = ?", p.ID, curLobby.ID).Delete(&LobbySlot{}) curLobby.Unlock() } } else { //player is in the same lobby, they're changing their slots //assign the player to a new slot if isSubstitution { //the slot needs a substitute (which happens when the lobby is in progress), //so players already in the lobby cannot fill it. return ErrNeedsSub } lobby.Lock() db.DB.Where("player_id = ? AND lobby_id = ?", p.ID, lobby.ID).Delete(&LobbySlot{}) lobby.Unlock() slotChange = true } } if !slotChange { //check if the player is in the steam group whitelist url := fmt.Sprintf(`http://steamcommunity.com/groups/%s/memberslistxml/?xml=1`, lobby.PlayerWhitelist) if lobby.PlayerWhitelist != "" && !helpers.IsWhitelisted(p.SteamID, url) { return ErrNotWhitelisted } //check if player has been subbed to the twitch channel (if any) //allow channel owners if lobby.TwitchChannel != "" && p.TwitchName != lobby.TwitchChannel { //check if player has connected their twitch account if p.TwitchAccessToken == "" { return errors.New("You need to connect your Twitch Account first to join the lobby.") } if lobby.TwitchRestriction == TwitchSubscribers && !p.IsSubscribed(lobby.TwitchChannel) { return fmt.Errorf("You aren't subscribed to %s", lobby.TwitchChannel) } if lobby.TwitchRestriction == TwitchFollowers && !p.IsFollowing(lobby.TwitchChannel) { return fmt.Errorf("You aren't following %s", lobby.TwitchChannel) } } } // Check if player is a substitute (the slot needs a subtitute) if isSubstitution { //get previous slot, to kick them from game prevPlayerID, _ := lobby.GetPlayerIDBySlot(slot) prevPlayer, _ := player.GetPlayerByID(prevPlayerID) lobby.Lock() db.DB.Where("lobby_id = ? AND slot = ?", lobby.ID, slot).Delete(&LobbySlot{}) lobby.Unlock() go func() { //kicks previous slot occupant if they're in-game, resets their !rep count, removes them from the lobby rpc.DisallowPlayer(lobby.ID, prevPlayer.SteamID, prevPlayer.ID) BroadcastSubList() //since the sub slot has been deleted, broadcast the updated substitute list //notify players in game server of subtitute class, team, _ := format.GetSlotTeamClass(lobby.Type, slot) rpc.Say(lobby.ID, fmt.Sprintf("Substitute found for %s %s: %s (%s)", team, class, p.Name, p.SteamID)) }() //allow player in mumble } //try to remove them from spectators lobby.RemoveSpectator(p, true) newSlotObj := &LobbySlot{ PlayerID: p.ID, LobbyID: lobby.ID, Slot: slot, } lobby.Lock() db.DB.Create(newSlotObj) lobby.Unlock() if !slotChange { if p.TwitchName != "" { rpc.TwitchBotAnnouce(p.TwitchName, lobby.ID) } } lobby.OnChange(true) p.SetMumbleUsername(lobby.Type, slot) return nil }
//AddPlayer adds the given player to lobby, If the player occupies a slot in the lobby already, switch slots. //If the player is in another lobby, removes them from that lobby before adding them. func (lobby *Lobby) AddPlayer(player *Player, slot int, password string) *helpers.TPError { /* Possible errors while joining * Slot has been filled * Player has already joined a lobby * anything else? */ //check if slot password is valid if lobby.SlotPassword != "" && lobby.SlotPassword != password { return InvalidPasswordErr } num := 0 //Check if player is banned //TODO(nonagon): It should really be possible to do this query using relations if err := db.DB.Table("banned_players_lobbies"). Where("lobby_id = ? AND player_id = ?", lobby.ID, player.ID). Count(&num).Error; num > 0 || err != nil { //logrus.Debug(fmt.Sprint(err)) return LobbyBanErr } if slot >= 2*NumberOfClassesMap[lobby.Type] || slot < 0 { return BadSlotErr } var slotChange bool //Check if the player is currently in another lobby if currLobbyID, err := player.GetLobbyID(false); err == nil { if currLobbyID != lobby.ID { //if the player is in a different lobby, remove them from that lobby //plus substitute them curLobby, _ := GetLobbyByID(currLobbyID) if curLobby.State == LobbyStateInProgress { curLobby.Substitute(player) } else { curLobby.RemovePlayer(player) curLobby.AddSpectator(player) } } else { //player is in the same lobby, they're changing their slots //assign the player to a new slot if lobby.SlotNeedsSubstitute(slot) { //the slot needs a substitute (which happens when the lobby is in progress), //so players already in the lobby cannot fill it. return NeedsSubErr } db.DB.Where("player_id = ? AND lobby_id = ?", player.ID, lobby.ID).Delete(&LobbySlot{}) slotChange = true } } if !slotChange { //check if the player is in the steam group whitelist url := fmt.Sprintf(`http://steamcommunity.com/groups/%s/memberslistxml/?xml=1`, lobby.PlayerWhitelist) if lobby.PlayerWhitelist != "" && !helpers.IsWhitelisted(player.SteamID, url) { return NotWhitelistedErr } if lobby.HasRequirements(slot) { //check if player fits the requirements for the slot if ok, err := lobby.FitsRequirements(player, slot); !ok { return err } } } // Check if player is a substitute (the slot needs a subtitute) if lobby.SlotNeedsSubstitute(slot) { //kicks previous slot occupant if they're in-game, resets their !rep count, removes them from the lobby DisallowPlayer(lobby.ID, player.SteamID) //delete previous slot db.DB.Where("lobby_id = ? AND slot = ?", lobby.ID, slot).Delete(&LobbySlot{}) BroadcastSubList() //since the sub slot has been deleted, broadcast the updated substitute list //notify players in game server of subtitute class, team, _ := LobbyGetSlotInfoString(lobby.Type, slot) Say(lobby.ID, fmt.Sprintf("Substitute found for %s %s: %s (%s)", team, class, player.Name, player.SteamID)) //allow player in mumble FumbleLobbyPlayerJoinedSub(lobby, player, slot) } else if _, err := lobby.GetPlayerIDBySlot(slot); err == nil { return FilledErr } else { FumbleLobbyPlayerJoined(lobby, player, slot) // no errors, al } //try to remove them from spectators lobby.RemoveSpectator(player, true) newSlotObj := &LobbySlot{ PlayerID: player.ID, LobbyID: lobby.ID, Slot: slot, } db.DB.Create(newSlotObj) lobby.OnChange(true) return nil }