func (l Conn) OnUserChange(e *gumble.UserChangeEvent) { l.client.Do(func() { switch { case e.Type.Has(gumble.UserChangeChannel): if !e.User.IsRegistered() { // this shouldn't happen, the mumble authenticator // is down, so we'll let users join channel by themselves e.User.Send("The mumble authentication service is down, please contact admins, or try reconnecting.") return } if e.User.Channel.IsRoot() { lobbyID, team := database.GetCurrentLobby(e.User.UserID) if lobbyID != 0 { moveUserToLobbyChannel(e.Client, e.User, lobbyID, team) return } } if allowed, reason := isUserAllowed(e.User, e.User.Channel); !allowed { e.User.Send(reason) lobbyID, team := database.GetCurrentLobby(e.User.UserID) if lobbyID != 0 { moveUserToLobbyChannel(e.Client, e.User, lobbyID, team) } else if !database.IsAdmin(e.User.UserID) { e.User.Move(e.Client.Channels[0]) } } else if !e.User.Channel.IsRoot() && !strings.HasPrefix(e.User.Channel.Name, "Lobby") { // user joined the correct team channel bytes, _ := json.Marshal(event.Event{ Name: event.PlayerMumbleJoined, PlayerID: e.User.UserID, }) // we don't need to know the lobby id, helen can do that amqpChannel.Publish( "", queueName, false, false, amqp.Publishing{ ContentType: "application/json", Body: bytes, }) } else { //Either the lobby ended, and the player joined //the root channel, in which case Helen wouldn't //do anything, or the player joined the root //channel while the lobby was going on, //in which case Helen changes the in-mumble //status for the player to false bytes, _ := json.Marshal(event.Event{ Name: event.PlayerMumbleLeft, PlayerID: e.User.UserID, }) amqpChannel.Publish( "", queueName, false, false, amqp.Publishing{ ContentType: "application/json", Body: bytes, }) } case e.Type.Has(gumble.UserChangeConnected): if !e.User.IsRegistered() { e.User.Send("The mumble authentication service is down, please contact admins, or try reconnecting.") } e.User.Send("Welcome to TF2Stadium!") case e.Type.Has(gumble.UserChangeDisconnected): bytes, _ := json.Marshal(event.Event{ Name: event.PlayerMumbleLeft, PlayerID: e.User.UserID, }) amqpChannel.Publish( "", queueName, false, false, amqp.Publishing{ ContentType: "application/json", Body: bytes, }) } }) }
func channelManage(conn *Conn) { for { select { case lobbyID := <-conn.Create: name := fmt.Sprintf("Lobby #%d", lobbyID) conn.lobbyRootWait.Add(1) conn.client.Do(func() { conn.client.Channels[0].Add(name, false) }) conn.lobbyRootWait.Wait() conn.client.Do(func() { channel := conn.client.Channels[0].Find(name) channel.SetDescription("Mumble channel for TF2Stadium " + name) log.Printf("#%d: Creating RED and BLU", lobbyID) channel.Add("RED", false) channel.Add("BLU", false) }) log.Printf("#%d: Done", lobbyID) case lobbyID := <-conn.Remove: name := fmt.Sprintf("Lobby #%d", lobbyID) conn.client.Do(func() { root := conn.client.Channels[0].Find(name) // root lobby channel if root == nil { log.Printf("Couldn't find channel `%s`", name) return } totalUsers := 0 for _, channel := range root.Children { totalUsers += len(channel.Users) channel.Remove() } if totalUsers == 0 { // no users in both channels, remove it entirely root.Remove() } else { root.Send("Removing channel after 10 minutes", false) time.AfterFunc(10*time.Minute, func() { conn.client.Do(func() { root := conn.client.Channels[0].Find(name) if root == nil { log.Printf("Couldn't find channel `%s`", name) return } root.Remove() }) }) } return }) log.Printf("#%d: Deleted channels", lobbyID) case userID := <-conn.RemoveUser: conn.client.Do(func() { for _, user := range conn.client.Users { if user.Channel.ID != 0 && user.UserID == uint32(userID) { user.Move(conn.client.Channels[0]) break } } }) case userID := <-conn.MoveUser: lobbyID, team := database.GetCurrentLobby(uint32(userID)) if lobbyID == 0 { continue } conn.client.Do(func() { for _, user := range conn.client.Users { if user.UserID == uint32(userID) { moveUserToLobbyChannel(conn.client, user, lobbyID, team) break } } }) } } }