func (r *Room) RemoveUser(user *User, connID string) error {
	if user == nil || len(user.name) == 0 {
		return errors.New("*Room.RemoveUser() requires a valid *User")
	} else if multiConnect && len(connID) == 0 {
		return errors.New("Must provide a connID when MultiConnect is enabled")
	} else if !multiConnect {
		connID = "1"
	}
	r.mux.Lock()
	if r.usersMap == nil {
		r.mux.Unlock()
		return errors.New("The room '" + r.name + "' does not exist")
	}
	var ok bool
	var ru *RoomUser
	if ru, ok = r.usersMap[user.name]; !ok {
		r.mux.Unlock()
		return errors.New("User '" + user.name + "' is not in room '" + r.name + "'")
	}
	ru.mux.Lock()
	var uConn *userConn
	if uConn, ok = ru.conns[connID]; !ok {
		r.mux.Unlock()
		ru.mux.Unlock()
		return errors.New("Invalid connID")
	}
	delete(ru.conns, connID)
	if len(ru.conns) == 0 {
		delete(r.usersMap, user.name)
	}
	ru.mux.Unlock()
	userList := r.usersMap
	r.mux.Unlock()
	roomType := roomTypes[r.rType]
	if deleteRoomOnLeave && user.name == r.owner {
		deleteErr := r.Delete()
		if deleteErr != nil {
			return deleteErr
		}
	} else if roomType.BroadcastUserLeave() {
		message := map[string]map[string]interface{}{
			helpers.ServerActionUserLeave: {
				"u": user.name,
			},
		}
		for _, u := range userList {
			u.mux.Lock()
			for _, conn := range u.conns {
				conn.socket.WriteJSON(message)
			}
			u.mux.Unlock()
		}
	}
	user.mux.Lock()
	uConn.room = nil
	user.mux.Unlock()
	if roomType.HasUserLeaveCallback() {
		roomType.UserLeaveCallback()(r, ru)
	}
	clientResp := helpers.MakeClientResponse(helpers.ClientActionLeaveRoom, r.Name(), helpers.NoError())
	uConn.socket.WriteJSON(clientResp)
	return nil
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
REMOVE A USER   //////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
RemoveUser removes a User from the room. If you are using MultiConnect in ServerSettings, the connID
parameter is the connection ID associated with one of the connections attached to that User. This must
be provided when removing a User from a Room with MultiConnect enabled. Otherwise, an empty string can be used.
package core
import (
	"errors"
	"github.com/hewiefreeman/GopherGameServer/helpers"
	"sync"
)
type Room struct {
	name     string
	rType    string
	private  bool
	owner    string
	maxUsers int
	mux        sync.Mutex
	inviteList []string
	usersMap   map[string]*RoomUser
	vars       map[string]interface{}
}
type RoomUser struct {
	user *User
	mux   sync.Mutex
	conns map[string]*userConn
}
var (
	rooms    map[string]*Room = make(map[string]*Room)
	roomsMux sync.Mutex
)
func NewRoom(name string, rType string, isPrivate bool, maxUsers int, owner string) (*Room, error) {
	if len(name) == 0 {
		return &Room{}, errors.New("core.NewRoom() requires a name")
	} else if maxUsers < 0 {
		maxUsers = 0
	} else if owner == "" {
		owner = serverName
	}
	var roomType *RoomType
	var ok bool
	if roomType, ok = roomTypes[rType]; !ok {
		return &Room{}, errors.New("Invalid room type")
	}
	roomsMux.Lock()
	if _, ok := rooms[name]; ok {
		roomsMux.Unlock()
		return &Room{}, errors.New("A Room with the name '" + name + "' already exists")
	}
	theRoom := Room{name: name, private: isPrivate, inviteList: []string{}, usersMap: make(map[string]*RoomUser), maxUsers: maxUsers,
		vars: make(map[string]interface{}), owner: owner, rType: rType}
	rooms[name] = &theRoom
	roomsMux.Unlock()
	if roomType.HasCreateCallback() {
		roomType.CreateCallback()(&theRoom)
	}
	return &theRoom, nil
}
func (r *Room) Delete() error {
	r.mux.Lock()
	if r.usersMap == nil {
		r.mux.Unlock()
		return errors.New("The room '" + r.name + "' does not exist")
	}
	leaveMessage := helpers.MakeClientResponse(helpers.ClientActionLeaveRoom, nil, helpers.NoError())
	for _, u := range r.usersMap {
		u.mux.Lock()
		for key := range u.conns {
			(*u.conns[key]).socket.WriteJSON(leaveMessage)
			u.user.mux.Lock()
			(*u.conns[key]).room = nil
			u.user.mux.Unlock()
		}
		u.mux.Unlock()
	}
	r.usersMap = nil
	r.mux.Unlock()
	roomsMux.Lock()
	delete(rooms, r.name)
	roomsMux.Unlock()
	rType := roomTypes[r.rType]
	if rType.HasDeleteCallback() {
		rType.DeleteCallback()(r)
	}
	return nil
}
func GetRoom(roomName string) (*Room, error) {
	if len(roomName) == 0 {
		return &Room{}, errors.New("core.GetRoom() requires a room name")
	}
	var room *Room
	var ok bool
	roomsMux.Lock()
	if room, ok = rooms[roomName]; !ok {
		roomsMux.Unlock()
		return &Room{}, errors.New("The room '" + roomName + "' does not exist")
	}
	roomsMux.Unlock()
	return room, nil
}
func (r *Room) AddUser(user *User, connID string) error {
	userName := user.Name()
	if user == nil {
		return errors.New("*Room.AddUser() requires a valid User")
	} else if multiConnect && len(connID) == 0 {
		return errors.New("Must provide a connID when MultiConnect is enabled")
	} else if !multiConnect {
		connID = "1"
	}
	r.mux.Lock()
	if r.usersMap == nil {
		r.mux.Unlock()
		return errors.New("The room '" + r.name + "' does not exist")
	} else if r.maxUsers != 0 && len(r.usersMap) == r.maxUsers {
		r.mux.Unlock()
		return errors.New("The room '" + r.name + "' is full")
	}
	if r.private && userName != r.owner {
		if len(r.inviteList) > 0 {
			for i := 0; i < len(r.inviteList); i++ {
				if (r.inviteList)[i] == userName {
					break
				}
				if i == len(r.inviteList)-1 {
					r.mux.Unlock()
					return errors.New("User '" + userName + "' is not on the invite list")
				}
			}
		} else {
			r.mux.Unlock()
			return errors.New("User '" + userName + "' is not on the invite list")
		}
	}
	var ru *RoomUser
	var ok bool
	if ru, ok = r.usersMap[userName]; ok {
		if !multiConnect {
			r.mux.Unlock()
			return errors.New("User '" + userName + "' is already in room '" + r.name + "'")
		}
		ru.mux.Lock()
		if _, ok := ru.conns[connID]; ok {
			r.mux.Unlock()
			ru.mux.Unlock()
			return errors.New("User '" + userName + "' is already in room '" + r.name + "'")
		}
		ru.mux.Unlock()
	}
	user.mux.Lock()
	c := user.conns[connID]
	if c == nil {
		r.mux.Unlock()
		return errors.New("Invalid connection ID")
	}
	if ru != nil {
		(*r.usersMap[userName]).mux.Lock()
		(*r.usersMap[userName]).conns[connID] = c
		(*r.usersMap[userName]).mux.Unlock()
	} else {
		conns := make(map[string]*userConn)
		conns[connID] = c
		newUser := RoomUser{user: user, conns: conns}
		r.usersMap[userName] = &newUser
		ru = r.usersMap[userName]
	}
	c.room = r
	user.mux.Unlock()
	r.mux.Unlock()
	roomType := roomTypes[r.rType]
	if roomType.BroadcastUserEnter() {
		message := map[string]map[string]interface{}{
			helpers.ServerActionUserEnter: {
				"u": userName,
				"g": user.isGuest,
			},
		}
		for _, u := range r.usersMap {
			u.mux.Lock()
			if u.user.Name() != userName {
				for _, conn := range u.conns {
					(*conn).socket.WriteJSON(message)
				}
			}
			u.mux.Unlock()
		}
	}
	if roomType.HasUserEnterCallback() {
		roomType.UserEnterCallback()(r, ru)
	}
	clientResp := helpers.MakeClientResponse(helpers.ClientActionJoinRoom, r.Name(), helpers.NoError())
	c.socket.WriteJSON(clientResp)
	return nil
}