func (r *Room) RemoveInvite(userName string) error {
	if !r.private {
		return errors.New("Room is not private")
	} else if len(userName) == 0 {
		return errors.New("*Room.RemoveInvite() requires a userName")
	}
	r.mux.Lock()
	if r.usersMap == nil {
		r.mux.Unlock()
		return errors.New("The room '" + r.name + "' does not exist")
	}
	for i := 0; i < len(r.inviteList); i++ {
		if r.inviteList[i] == userName {
			r.inviteList[i] = r.inviteList[len(r.inviteList)-1]
			r.inviteList = r.inviteList[:len(r.inviteList)-1]
			break
		}
		if i == len(r.inviteList)-1 {
			r.mux.Unlock()
			return errors.New("User '" + userName + "' is not on the invite list")
		}
	}
	r.mux.Unlock()
	return nil
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
REMOVE FROM inviteList   /////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
RemoveInvite removes a User from a private Room's invite list. To make a User remove someone from their room themselves,
use the *User.RevokeInvite() function.

NOTE: You can use this function safely, but remember that private rooms are designed to have an "owner",
and only the owner should be able to send an invite and revoke an invitation for their Rooms. But if you find the
need to break the rules here, by all means do so!
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
}
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
}
func (r *Room) AddInvite(userName string) error {
	if !r.private {
		return errors.New("Room is not private")
	} else if len(userName) == 0 {
		return errors.New("*Room.AddInvite() requires a userName")
	}
	r.mux.Lock()
	if r.usersMap == nil {
		r.mux.Unlock()
		return errors.New("The room '" + r.name + "' does not exist")
	}
	for i := 0; i < len(r.inviteList); i++ {
		if r.inviteList[i] == userName {
			r.mux.Unlock()
			return errors.New("User '" + userName + "' is already on the invite list")
		}
	}
	r.inviteList = append(r.inviteList, userName)
	r.mux.Unlock()
	return nil
}