Skip to content
Dominique Debergue edited this page Aug 26, 2019 · 17 revisions

You can think of a core.Room as a place on the server where a core.User can enter to interact with other Users. Rooms can be created by the server, or by a client if your custom server rules allow it. Before a Room can be made, the server needs to know what type of Rooms can be made, and only those types of Room will be accepted for creation.

⚠️ Warning: When you have a *core.Room pointer in your code, DO NOT de-reference it. Instead, there are many methods for *Room for retrieving any information about them you could possibly need. De-referencing them could cause data races (which will panic and stop the server) in the Room fields that get locked for synchronizing access.

📘 Room Types

A RoomType defines a type of room that can be made on the server. RoomTypes can only be created before starting the server. Here's an example of how to use the NewRoomType() method to make a RoomType:

package main

import (
	"github.com/hewiefreeman/GopherGameServer"
	"github.com/hewiefreeman/GopherGameServer/core"
)

func main() {
	// Make a RoomType
	rt := core.NewRoomType("gameRoom", true)

	// Start the server
	gopher.Start(nil)
}

This creates a new RoomType named "gameRoom" before starting the server. The second boolean parameter makes the room a server-only room when true, which means clients cannot create, destroy, or manipulate Rooms of that RoomType in any way.

📘 Room Broadcasts

RoomTypes can have broadcasts set for when a User enters or leaves. A broadcast sends a message to all Users in the Room notifying them that another User has entered or left the room. You can set the broadcasts for a RoomType when creating one with the EnableBroadcastUserEnter() and EnableBroadcastUserLeave() methods:

package main

import (
	"github.com/hewiefreeman/GopherGameServer"
	"github.com/hewiefreeman/GopherGameServer/core"
)

func main() {
	// Make a RoomType
	rt := core.NewRoomType("gameRoom", true)

	// Enable broadcasts
	rt.EnableBroadcastUserEnter()
	rt.EnableBroadcastUserLeave()
	// Can also be typed like:
	// rt.EnableBroadcastUserEnter().EnableBroadcastUserLeave()

	// Start the server
	gopher.Start(nil)
}

Now, when a User enters a Room of type "gameRoom", all other Users in the room will be sent a message notifying them of the entrance. Same goes for when a User leaves a Room of that type.

📘 Room Callbacks

RoomTypes can have callbacks set for when you want to run your own code when a specific action is taken upon it. RoomTypes have 4 callbacks: create, delete, User enter, and User leave. They can be set with the methods SetCreateCallback(), SetDeleteCallback(), SetUserEnterCallback(), and SetUserLeaveCallback():

package main

import (
	"github.com/hewiefreeman/GopherGameServer"
	"github.com/hewiefreeman/GopherGameServer/core"
)

func main() {
	// Make a RoomType
	rt := core.NewRoomType("gameRoom", true)

	// Set callbacks
	rt.SetCreateCallback(onCreateGameRoom)
	rt.SetDeleteCallback(onDeleteGameRoom)
	rt.SetUserEnterCallback(onEnterGameRoom)
	rt.SetUserLeaveCallback(onLeaveGameRoom)

	// Start the server
	gopher.Start(nil)
}

func onCreateGameRoom(room *core.Room) {
	// Code to run after a Room of type "gameRoom" is created
}

func onDeleteGameRoom(room *core.Room) {
	// Code to run after a Room of type "gameRoom" is deleted
}

func onEnterGameRoom(room *core.Room, roomUser *core.RoomUser) {
	// Code to run after a User enters a Room of type "gameRoom"
	// To get the *User:
	// u := roomUser.User()
}

func onLeaveGameRoom(room *core.Room, roomUser *core.RoomUser) {
	// Code to run after a User leaves a Room of type "gameRoom"
	// To get the *User:
	// u := roomUser.User()
}

The create and delete callback functions need to accept a *core.Room, which you can use to manipulate the newly created (or deleted) Room, or whatever else you may want to do with it. The enter and leave callbacks accept a *core.Room as well as a *core.RoomUser, which represents the entering/leaving User. You can use the *RoomUser.User() method to get the *User from a *RoomUser, as per the example above.

📘 Creating & Deleting Rooms

The methods to create and delete Rooms are core.NewRoom() and *Room.Delete():

package main

import (
	"github.com/hewiefreeman/GopherGameServer"
	"github.com/hewiefreeman/GopherGameServer/core"
	"fmt"
	"time"
)

func main() {
	// Make a RoomType
	core.NewRoomType("gameRoom", true)

	// Make a new Room named "game#958427" of type "gameRoom"
	room, roomErr := core.NewRoom("game#958427", "gameRoom", false, 20, "")
	if roomErr != nil {
		fmt.Println(roomErr)
		return
	}

	// Run a goroutine that deletes the room after 15 seconds
	go deleteRoom(room)

	// Start the server
	gopher.Start(nil)
}

func deleteRoom(room *core.Room) {
	// Sleep goroutine for 15 seconds
	time.Sleep(time.Second * 15)

	// Delete the previously created Room
	room.Delete()
}

In the main thread I've created a RoomType and a Room of that type, caught any error that might have happened creating the Room, ran a goroutine, and started the server. The spawned goroutine waits 15 seconds, then deletes the new Room created from the main thread. This is just a simple program to showcase creating and deleting a Room.

📘 Room Variables

Room variables provide you with a means of storing and receiving data attached to a room. You can set a Room variable with *Room.SetVariable(), or multiple at once with *Room.SetVariables(). Likewise, you can get a Room variable with *Room.GetVariable(), or multiple with *Room.GetVariables(). Here's an example using all four methods:

// Make a Room
room, roomErr := core.NewRoom("test", "game", false, 0, "")
if roomErr != nil {
	fmt.Println(roomErr)
	return
}

// Set a Room variable
room.SetVariable("team1Points", 0)

// Make or use a map[string]interface{} to set multiple Room variables at once
varMap := map[string]interface{}{
	"team2Points": 0,
	"team1Players": []string{},
	"team2Players": []string{},
}
room.SetVariables(varMap)

// Get a single Room variable at a time
t1Points, _ := room.GetVariable("team1Points") // Expected: 0
something, _ := room.GetVariable("doesntExist") // Expected: nil

// Get multiple Room variables at a time
t2, _ := room.GetVariables([]string{"team2Points", "team2Players"}) // Expected: map["team2Points": 0, "team2Players": []]

📘 Messaging

Chat Messaging

Chat messaging is taken care of by the client API. All Rooms have chat built-in and does not require any additional configuration on the server side. Though, if you wish to send a fake chat message to a Room you can use the *Room.ChatMessage() method described in the documentation. Notice the method takes in an interface{}. This allows chat messages to use any data type compatible with JSON, so you can send almost any sort of information along with your chat messages.

Voice Chat

Much like chat messaging, voice chat is (for the most part) taken care of by the client API. The only difference is you need to enable voice chat for your RoomTypes. You can enable voice chat for a RoomType with the *RoomType.EnableVoiceChat method:

// Make a RoomType
gameRoomType := core.NewRoomType("gameRoom", true)

// Enable voice chat for "gameRoom" RoomType
gameRoomType.EnableVoiceChat()

Server Messages

A server message is essentially a chat message generated and sent from the server itself for any notices, warnings, etc. You can send a server message to a room with the *Room.ServerMessage() method:

message := "Team 1 wins!"
messageType := core.ServerMessageGame
room.ServerMessage(message, messageType, nil)

ServerMessage() takes in a message, message type, and a list of recipients. The message can be any data type compatible with JSON (like chat messages), and the message type is an integer that you can either make custom definitions for, or use one of ServerMessageGame, ServerMessageNotice, or ServerMessageImportant. The recipients is a slice of string that lists the User name of the Users you want to send the message to. A nil recipient list will send the message to all users in the Room.

Data Messages

A data message is also a message generated and sent directly from the server. Unlike a server message, a data message's primary usage is to send some sort of data to Users in the Room as efficiently as possible. A data message is more efficient for sending real-time data to Users because it doesn't come with an author (like chat messages), or a message type (like server messages). Only the data itself is sent. You can send a data message with the *Room.DataMessage() method:

data := make(map[string]interface{})
data[x] = 12
data[y] = 56
room.DataMessage(data, nil)

The second parameter in DataMessage() is a recipients list, and works exactly like the recipients list in ServerMessage(). You can either pass a slice of string with a list of User names, or nil to send the data message to all Users in the Room.

If you notice there is lacking information, missing features, or bad explanations, please open an issue. All requests are acceptable and will be taken into consideration.

Clone this wiki locally