func Add(mid, uqid, tag string, props map[string]int, value map[string]interface{}, ttl int64, limit int) error
Add Adds a searchable matching candidate data.
[NOTE] In order to have long lasting (TTL longer than 60 seconds) searchable items, the application must "add" searchable items repeatedly with TTL=60. [NOTE] Uses mutex lock internally.
Error Cases
╒═════════════════════╤══════════════════════════════════════════════════════════╕ │ Error │ Reason │ ╞═════════════════════╪══════════════════════════════════════════════════════════╡ │ Invalid profile IDs │ Either missing or invalid matchmaking profile IDs given. │ ├─────────────────────┼──────────────────────────────────────────────────────────┤ │ Unique ID missing │ Unique ID must not be an empty string. │ ├─────────────────────┼──────────────────────────────────────────────────────────┤ │ Properties missing │ Properties must not be a nil. │ ├─────────────────────┼──────────────────────────────────────────────────────────┤ │ Invalid limit value │ Limit must be greater than 1. │ ╘═════════════════════╧══════════════════════════════════════════════════════════╛
Parameters
mid - Matching profile ID to add the searchable data to. unqiueID - Unique ID of the searchable ID. tag - Tag is used to isolate and group add and search of matchmaking. If an empty string is given, it will be ignored. props - Searchable condition properties. value - Searchable data to be returned along with the search results. ttl - TTL of the searchable item to be added in seconds. Maximum 60 seconds. limit - Number of search node to propagate the searchable item data at a time.
func CancelTicket(ticketType uint8, userData *user.User) error
CancelTicket stops ticket-based matchmaking started by StartTicket.
Canceling a ticket will disband the matchmaking and remove already-matched users from it.
[IMPORTANT] Only the owner user of the ticket are allowed to cancel the ticket. [IMPORTANT] CancelTicket will fail after the completion of the ticket. [NOTE] Uses mutex lock internally.
Error Cases
┌───────────────────────┬───────────────────────────────────────────────────────────┐ │ Error │ Reason │ ╞═══════════════════════╪═══════════════════════════════════════════════════════════╡ │ Ticket not found │ The ticket to cancel is not available. │ │ Ticket failed to stop │ The ticket is not active (already completed or canceled). │ │ User not found │ The user was not found. │ └───────────────────────┴───────────────────────────────────────────────────────────┘
Parameters
ticketType - Ticket type of the ticket to cancel. userData - The owner user of the ticket to cancel.
func ClearDefinition(matchingID string)
ClearDefinition clears already defined match making definition
matchingID - Matching profile ID to clear the definition.
func ControlTicketParams(params *TicketParams) (int64, int64)
ControlTicketParams [INTERNALLY USED ONLY]
func CreateKeyByProperties(matchingID string, tag string, properties map[string]int) string
CreateKeyByProperties generates a key from a tag and search or add properties.
This is meant to be used along with DebugDataDump for test and debugging.
The key generated is the actual search condition data used internally to find matches.
func DebugDataDump() (map[string][]*searchItem, error)
DebugDataDump returns the entire matchmaking data held in memory of the server.
[IMPORTANT] This is a debug function and must NOT be used in production code at all. [NOTE] In order to evaluate key, use CreateKeyByProperties to reproduce the same key with property values that match. [NOTE] Uses mutex lock internally.
Example of evaluating the dump data keys:
dump := matching.DebugDataDump() for key, searchItems := range dump { // expected key expectedKey := matching.CreateKeyByProperties(profileID, tag, expectedProperties) // check to see if the key matches the expected key if key == expectedKey { // good } else { // bad... } }
func DebugDataDumpWriter(writer io.Writer) error
DebugDataDumpWriter writes the entire matchmaking data held in memory of the server to io.Writer stream.
[IMPORTANT] This is a debug function and must NOT be used in production code at all. [NOTE] In order to evaluate key, use CreateKeyByProperties to reproduce the same key with property values that match. [NOTE] Uses mutex lock internally.
func Define(profileID string, props map[string]int)
Define defines a match making search schema:
[IMPORTANT] This must be defined on the server that is specified by "targetNodeType" configuration because all match making data is stored on those servers. [IMPORTANT] Profile ID must not contain "\t".
Parameters
profileID - Unique matching profile ID. props - Matching profile condition properties.
In order to perform matchmaking, you must define the rules for matchmakings.
The matchmaking rules are called profiles.
These rules will dictate how matchmaking should be conditioned.
You may combine multiple matchmaking rules and create more complex matchmaking conditions as well.
You must define matchmaking rule profiles before invoking diarkis.Start.
The example below shows a matchmaking rule that uses level and creates buckets of matchmaking pools by the range of 10.
With this profile, each level bucket will pool users with level 0 to 10, 11 to 20, 21 to 30 and so forth...
The string name given as LevelMatch is the unique ID to represents the profile.
levelMatchProfile := make(map[string]int) levelMatchProfile["level"] = 10 matching.Define("LevelMatch", levelMatchProfile)
You may define as many matching definition as you require as long as each profileID is unique.
func DefineByJSON(jsonBytes []byte)
DefineByJSON defines multiple match making definitions from JSON string.
$(...) represents a variable.
{ "$(profile ID)": { "$(property name)": $(property value as int) "$(property name)": $(property value as int) "$(property name)": $(property value as int) } } jsonBytes - Matching profile byte array data to be used to define the profile.
func ExposeCommands()
ExposeCommands exposes built-in commands to the client.
func GenerateTicketFailurePayload(message string, code uint16) []byte
GenerateTicketFailurePayload generates a payload for ticket failure.
func GetTicketMemberIDs(ticketType uint8, userData *user.User) ([]string, bool)
GetTicketMemberIDs returns the list of matched member user IDs.
Cases for the second return value to be false
When the internal room is missing.
When non-owner user executes the function.
[IMPORTANT] This function is available ONLY for the owner of the ticket.
[NOTE] Uses mutex lock internally.
func GetTicketMemberSIDs(ticketType uint8, userData *user.User) ([]string, bool)
GetTicketMemberSIDs returns the list of matched member user SIDs.
Cases for the second return value to be false
Highlights
[IMPORTANT] This function is available ONLY for the owner of the ticket. [IMPORTANT] If non-user uses this function it returns an empty array. [NOTE] Uses mutex lock internally.
func GetTicketProperties(ticketType uint8, userData *user.User, keys []string) (map[string]interface{}, bool)
GetTicketProperties returns key and value pairs as a map.
Cases for the second return value to be false
When the internal room is missing.
When non-owner user executes the function.
When the given property key does not exist.
[IMPORTANT] This function is available ONLY for the owner of the ticket. [IMPORTANT] Properties are only primitive values and does not support reference type data such as array and map. [IMPORTANT] If a value of a given key does not exist, the returned map will have a nil as a value of the key. [IMPORTANT] The returned property value is an interface{}, in order to type assert safely, please use Diarkis' util package functions.
[NOTE] Uses mutex lock internally.
Example
values, ok := GetTicketProperties(ticketType, userData, []string{ "someKey" }) if !ok { // handle error here } for key, v := range values { // If the value data type is an uint8, of course ;) value, ok := util.ToUint8(v) }
func GetTicketProperty(ticketType uint8, userData *user.User, key string) (interface{}, bool)
GetTicketProperty returns the value of the given key and if the key does not exist, the second return value will be a false.
Cases for the second return value to be false
When the internal room is missing.
When non-owner user executes the function.
When the given property key does not exist.
[IMPORTANT] This function is available ONLY for the owner of the ticket. [IMPORTANT] Properties are only primitive values and does not support reference type data such as array and map. [IMPORTANT] The returned property value is an interface{}, in order to type assert safely, please use Diarkis' util package functions.
[NOTE] Uses mutex lock internally.
Example
v, ok := GetTicketProperty(ticketType, userData, "someKey") if !ok { // handle error here } // If the value data type is an uint8, of course ;) v, ok := util.ToUint8(v)
func HasTicket(ticketType uint8, userData *user.User) bool
HasTicket returns true if the user given has a matchmaking ticket of the given type in progress.
func IsAddError(err error) bool
IsAddError returns true if the given error is or contain Add error.
func IsExportTicketError(err error) bool
IsExportTicketError returns true if the given error is or contain ExportTicket error.
func IsImportTicketError(err error) bool
IsImportTicketError returns true if the given error is or contain ImportTicket error.
func IsMarkAsCompleteError(err error) bool
IsMarkAsCompleteError returns true if the given error is or contain MarkAsComplete error.
func IsSearchError(err error) bool
IsSearchError returns true if the given error is or contain Search error.
func IsTicketAddError(err error) bool
IsTicketAddError returns true if the given error is or contain TicketAdd error.
func IsTicketBackfillError(err error) bool
IsTicketBackfillError returns true if the given error is or contain TicketBackfill error.
func IsTicketBroadcastError(err error) bool
IsTicketBroadcastError returns true if the given error is or contain TicketBroadcast error.
func IsTicketCancelError(err error) bool
IsTicketCancelError returns true if the given error is or contain TicketCancel error.
func IsTicketCreateError(err error) bool
IsTicketCreateError returns true if the given error is or contain TicketCreate error.
func IsTicketJoinError(err error) bool
IsTicketJoinError returns true if the given error is or contain TicketJoin error.
func IsTicketKickError(err error) bool
IsTicketKickError returns true if the given error is or contain TicketKick error.
func IsTicketLeaveError(err error) bool
IsTicketLeaveError returns true if the given error is or contain TicketLeave error.
func IsTicketOwner(ticketType uint8, userData *user.User) bool
IsTicketOwner returns true if the given user is the owner of its ticket
[NOTE] Uses mutex lock internally.
func IsTicketPropertySetError(err error) bool
IsTicketPropertySetError returns true if the given error is or contain TicketPropertySet error.
func IsTicketPropertyUpdateError(err error) bool
IsTicketPropertyUpdateError returns true if the given error is or contain TicketPropertyUpdate error.
func IsTicketSearchError(err error) bool
IsTicketSearchError returns true if the given error is or contain TicketSearch error.
func IsTicketStartError(err error) bool
IsTicketStartError returns true if the given error is or contain TicketStart error.
func IsUserInTicketMatchmaking(ticketType uint8, userData *user.User) bool
IsUserInTicketMatchmaking returns true if the user is matched with at least one another user in ticket matchmaking of the given ticket type.
The function returns true when:
1. The ticket the user created moves to "waiting" phase.
2. The ticket finds and joins another ticket.
[NOTE] If the user is in a ticket matchmaking, the user is able to send and receive TicketBroadcast messages and perform other ticket-related operations. [NOTE] Uses mutex lock internally.
func JoinRoomByID(ticketType uint8, id string, userData *user.User, cb func(error))
JoinRoomByID allows the user given to join a MatchMaker Ticket Room.
[IMPORTANT] MatchMaker Ticket Rooms are NOT the same as Room module.
func KickoutFromTicket(ticketType uint8, owner *user.User, targetUserID string, cb func(err error))
KickoutFromTicket forcefully removes a matched member from the matchmaking ticket.
[IMPORTANT] Only the owner of the ticket may execute this operation. [NOTE] Uses mutex lock internally.
Error Cases
╒═══════════════════════════╤═════════════════════════════════════════════════════════════════════════════╕ │ Error │ Reason │ ╞═══════════════════════════╪═════════════════════════════════════════════════════════════════════════════╡ │ MatchMaker room not found │ The owner user is not in a matchmaking ticket room. │ ├───────────────────────────┼─────────────────────────────────────────────────────────────────────────────┤ │ Must be the owner │ Only the owner of the ticket may kick out matched members. │ ├───────────────────────────┼─────────────────────────────────────────────────────────────────────────────┤ │ Target user not found │ The target user to kick out is not a matched member. │ ╘═══════════════════════════╧═════════════════════════════════════════════════════════════════════════════╛
func LeaveFromTicketMatchmaking(ticketType uint8, userData *user.User) bool
LeaveFromTicketMatchmaking makes the target user leave the matchmaking that the user has matched and joined.
[NOTE] Uses mutex lock internally.
func LeaveFromTicketMatchmakingWithCallback(ticketType uint8, userData *user.User, cb func(err error))
LeaveFromTicketMatchmakingWithCallback makes the target user leave the matchmaking that the user has matched and joined.
[NOTE] Uses mutex lock internally.
func MarkTicketAsComplete(ticketType uint8, userData *user.User) error
MarkTicketAsComplete finishes the ticket as complete immediately.
[IMPORTANT] Only the owner user of the ticket may execute this function. [NOTE] Uses mutex lock internally.
Error Cases
╒═══════════════════════╤═════════════════════════════════════════════════════════════════════════════╕ │ Error │ Reason │ ╞═══════════════════════╪═════════════════════════════════════════════════════════════════════════════╡ │ Ticket not found │ Either the ticket is not available or the given user does not own a ticket. │ ├───────────────────────┼─────────────────────────────────────────────────────────────────────────────┤ │ User is not owner │ User given is not the owner of the ticket. │ ├───────────────────────┼─────────────────────────────────────────────────────────────────────────────┤ │ Ticket room not found │ Internal room of the ticket is missing. │ │ │ Most likely due of an internal bug causing the ticket data to be corrupt. │ ╘═══════════════════════╧═════════════════════════════════════════════════════════════════════════════╛
Parameters
ticketType - Ticket type. userData - Owner user of the ticket to mark as complete.
func MarkTicketAsCompleteWhenExpire(ticketType uint8, userData *user.User) bool
MarkTicketAsCompleteWhenExpire marks the ticket as complete, but it will wait until the ticket expires.
[IMPORTANT] Only the owner of the ticket may execute this function. [NOTE] Uses mutex lock internally.
This is useful when you need to have alternative conditions for matchmaking completion without having all expected members match.
func ParseTicketFailurePayload(payload []byte) (string, uint16, error)
ParseTicketFailurePayload parses the payload of ticket failure push.
func Remove(matchingID string, uniqueIDList []string, limit int)
Remove removes a list of searchable matching candidate items by their unique IDs
[NOTE] This function is very expensive as it will send a message to all related mesh nodes [NOTE] There maybe some delay with removal operation on multiple servers as the instruction to remove must traverse all servers in the cluster.
Parameters
matchingID - Target matching profile ID to remove items from uniqueIDList - A list of unique IDs of the searchable items to remove limit - Mesh network relay limit
func Search(profileIDList []string, tag string, props map[string]int, limit int, callback func(err error, results []interface{}))
Search searches for matched data based on the given props' values
[IMPORTANT] Search performs search operations on remote servers and the number of servers to perform the search is calculated based on the number of the server and distributionRate configuration. This means that there is a chance that Search function may miss the server(s) with the desired matchmaking data resulting in not finding the intended matchmaking data. [NOTE] Uses mutex lock internally.
Error Cases
╒═════════════════════╤══════════════════════════════════════════════════════════════╕ │ Error │ Reason │ ╞═════════════════════╪══════════════════════════════════════════════════════════════╡ │ Invalid profile IDs │ Either missing or invalid matchmaking profile IDs give. │ ├─────────────────────┼──────────────────────────────────────────────────────────────┤ │ Invalid properties │ Either missing or invalid properties given. │ ├─────────────────────┼──────────────────────────────────────────────────────────────┤ │ Reliable timeout │ Communication to another server process timed out or failed. │ ╘═════════════════════╧══════════════════════════════════════════════════════════════╛
Parameters
profileIDList - A list of matchmaking profile IDs to search by. The order of the list is the order of search attempts. tag - A tag is used to isolate and group search meaning the search will not include tags that do not match. props - A property map to act as match making conditions. limit - A hard limit to the number of results. callback - A callback with the search results or an error.
func SearchWithRange(profileIDList []string, tag string, searchProps map[string][]int, limit int, callback func(err error, results []interface{}))
SearchWithRange searches for matched data based on the given values of props in range.
Each props will have an array of elements with property values that should range from minimum value to maximum value. The function will use those values per property to performance the search.
[IMPORTANT] SearchWithRange performs search operations on remote servers and the number of servers to perform the search is calculated based on the number of the server and distributionRate configuration. This means that there is a chance that SearchWithRange function may miss the server(s) with the desired matchmaking data resulting in not finding the intended matchmaking data. [IMPORTANT] The number of allowed range properties is limited to two.
Example:
searchProps["level"] = []int{ 1, 2, 3, 4, 5 } // range property searchProps["rank"] = []int{ 1, 2, 3 } // range property searchProps["matchType"] = []int{ 1 } // regular property searchProps["league"] = []int{ 10 } // regular property
Error Cases
╒═════════════════════╤══════════════════════════════════════════════════════════════╕ │ Error │ Reason │ ╞═════════════════════╪══════════════════════════════════════════════════════════════╡ │ Invalid profile IDs │ Either missing or invalid matchmaking profile IDs give. │ ├─────────────────────┼──────────────────────────────────────────────────────────────┤ │ Invalid properties │ Either missing or invalid properties given. │ ├─────────────────────┼──────────────────────────────────────────────────────────────┤ │ Reliable timeout │ Communication to another server process timed out or failed. │ ╘═════════════════════╧══════════════════════════════════════════════════════════════╛
Parameters
profileIDList - A list of matchmaking profile IDs to search by. The order of the list is the order of search attempts. tag - A tag is used to isolate and group search meaning the search will not include tags that do not match. searchProps - A map with search condition values. You are allowed to have maximum two properties with range (more than 1 element in the int array). If you have more than two elements with range, it will give you an error. limit - A hard limit to the number of results. callback - A callback with the search results or an error.
Diagram below shows how it works:
┏━━━┓ ┃ 8 ┃ 8 with ±3 would fall into 5 ~ 11 and that means it matches with items in the bucket of 0 to 10 and 11 to 20 ┗━┳━┛ ┏━┻━━━━┓ │ ▼ │ ▼ │ │ │ 0 ~ 10 │ 11 ~ 20 │ 21 ~ 30 │ └─────────┴─────────┴─────────┘
To make ranged search more precise, consider using SetOnTicketAllowMatchIf callback for MatchMaker Ticket.
func SearchWithRangeWithTags(profileIDList []string, tags []string, searchProps map[string][]int, limit int, callback func(err error, results []interface{}))
SearchWithRangeWithTags searches for matched data based on the given values of props in range with multiple tags. Search will be performed with the array of tags. Shuffle the tags before calling this function if needed. See SearchWithRange for more information.
func SetCustomJoinCondition(callback func(string, *user.User) bool)
SetCustomJoinCondition assigns a on join evaluation callback to be called to evaluate if the user should join or not
func SetOnDeleteTicketRoom(ticketType uint8, userData *user.User, callback func(id string)) bool
SetOnDeleteTicketRoom assigns a callback which is triggered when a matching room is deleted.
[IMPORTANT] This function is available ONLY for the owner of the ticket. [NOTE] Uses mutex lock internally. [NOTE] The callback is invoked while the lock is still being held. Avoid using locks in the callback to prevent mutex deadlocks.
func SetOnIssueTicket(ticketType uint8, cb func(userData *user.User) *TicketParams) bool
SetOnIssueTicket assigns a callback to be invoked when the built-in command issue ticket is called.
Parameters
ticketType - Ticket type is used to group tickets. It will assign the callback to the given ticket type. cb - Callback to be invoked and expected to create and return TicketParams for a new ticket.
The callback is invoked for the owner user only.
Calling StartTicket triggers this callback and TicketParams that it returns will be used to create a new ticket.
[CRITICALLY IMPORTANT] Using pointer variables that are defined outside of the callback closure in the callback closure will cause those pointers to be not garbage collected leading to memory leak. [IMPORTANT] This callback must be assigned to the appropriate ticket type in order for StartTicket(ticketType uint8, userData *user.User) to work properly. [IMPORTANT] userData maybe nil if the user disconnects from the server.
func SetOnLeaveTicketRoom(ticketType uint8, userData *user.User, callback func(id string, userData *user.User)) bool
SetOnLeaveTicketRoom assigns a callback which is triggered when a member leaves a matching room.
ticket.OnMatchedMemberLeave is valid only while ticket exists whereas this will be triggered also after the ticket completion.
[IMPORTANT] This function is available ONLY for the owner of the ticket. [NOTE] Uses mutex lock internally. [NOTE] The callback is invoked while the lock is still being held. Avoid using locks in the callback to prevent mutex deadlocks.
func SetOnMatchedTicketCanceled(ticketType uint8, cb func(ownerID string, userData *user.User)) bool
SetOnMatchedTicketCanceled assigns a callback to be invoked when a ticket that the user has joined is canceled.
[CRITICALLY IMPORTANT] Using pointer variables that are defined outside of the callback closure in the callback closure will cause those pointers to be not garbage collected leading to memory leak. [IMPORTANT] The callback is invoked for the non-owner users of the ticket only. For the ticket owner, OnTicketCancled will be invoked. [IMPORTANT] When the owner of the ticket either disconnects or re-connects to another server, the ticket will be canceled automatically. Cancel event is raised event after the completion of the ticket when the owner of the ticket disconnects or re-connects..
Parameters
ticketType - Ticket type is used to group tickets. It will assign the callback to the given ticket type. cb - Callback to be invoked when a ticket is canceled.
func SetOnMatchedTicketTimeout(ticketType uint8, cb func(ownerID string, userData *user.User)) bool
SetOnMatchedTicketTimeout assigns a callback to be invoked when a ticket that the user has joined is timed out.
[CRITICALLY IMPORTANT] Using pointer variables that are defined outside of the callback closure in the callback closure will cause those pointers to be not garbage collected leading to memory leak. [IMPORTANT] The callback is invoked for the non-owner users of the ticket only. For the ticket owner, OnTicketTimeout will be invoked.
Parameters
ticketType - Ticket type is used to group tickets. It will assign the callback to the given ticket type. cb - Callback to be invoked when a ticket times out.
func SetOnTicketAllowMatchIf(ticketType uint8, cb func(ticketProps *TicketProperties, owner, candidate *user.User) bool) bool
SetOnTicketAllowMatchIf assigns a callback to be invoked before a match is made to add a custom logic to control if the match found should proceed forward to become an actual match or not..
ticketType - Ticket type is used to group tickets. It will assign the callback to the given ticket type. callback - Callback to be called func(ticketProps *TicketProperties, owner *user.User, candidate *user.User) bool
If the callback returns true, a match will be made.
The callback is invoked for the owner user only.
[CRITICALLY IMPORTANT] Using pointer variables that are defined outside of the callback closure in the callback closure will cause those pointers to be not garbage collected leading to memory leak. [IMPORTANT] The callback is invoked while the ticket is holding the mutex lock, In order to avoid mutex deadlock, you must not invoke functions that uses mutex lock or retrieve a mutex lock in the callback. [IMPORTANT] Candidate is the user that has been matched and attempting to join the matched member room. [IMPORTANT] owner and/or candidate maybe nil if owner and/or candidate disconnects from the server.
func SetOnTicketCanceled(ticketType uint8, cb func(owner *user.User)) bool
SetOnTicketCanceled assigns a callback to be invoked when an issued ticket has been canceled.
[CRITICALLY IMPORTANT] Using pointer variables that are defined outside of the callback closure in the callback closure will cause those pointers to be not garbage collected leading to memory leak. [IMPORTANT] The callback is invoked only for the owner user of the ticket. For the non-owner users, OnMatchedTicketCancled will be invoked. [IMPORTANT] Owner maybe nil if owner is disconnected from the server.
Parameters
ticketType - Ticket type is used to group tickets. It will assign the callback to the given ticket type. cb - Callback to be invoked when a ticket is canceled.
func SetOnTicketComplete(ticketType uint8, cb func(ticketProps *TicketProperties, owner *user.User) []byte) bool
SetOnTicketComplete assigns a callback to be invoked when an issued ticket successfully completes.
[CRITICALLY IMPORTANT] Using pointer variables that are defined outside of the callback closure in the callback closure will cause those pointers to be not garbage collected leading to memory leak. [IMPORTANT] The callback is invoked only for the owner user of the ticket. [IMPORTANT] Owner maybe nil if owner disconnects from the server.
Parameters
ticketType - Ticket type is used to group tickets. It will assign the callback to the given ticket type. cb - Callback to be invoked when a matchmaking is complete.
The callback is invoked for the owner user of the ticket only.
The callback function must return a message byte array to be sent to all matched user clients.
func SetOnTicketMatch(ticketType uint8, cb func(ticket *Ticket, matchedUser, ownerUser *user.User, roomID string, memberIDs []string) bool) bool
SetOnTicketMatch assigns a callback to be invoked when a new match is made.
ticketType - Ticket type is used to group tickets. It will assign the callback to the given ticket type. cb - Callback to control if the match completes the matchmaking or not. Room ID passed to the callback is NOT Diarkis Room's ID, but it is the ID of the internal matchmaking room. func(ticket *Ticket, matchedUserData *user.User, owner *user.User, roomID string, memberIDs []string) bool
This callback is meant to execute a custom logic for matchmaking completion on every match found.
Having the callback return true will automatically completes the matchmaking.
The callback is invoked for the owner user only.
[CRITICALLY IMPORTANT] Using pointer variables that are defined outside of the callback closure in the callback closure will cause those pointers to be not garbage collected leading to memory leak. [IMPORTANT] callback is invoked for the owner of the ticket only. [IMPORTANT] matchedUser is a copy of the actual user data of *user.User because the matched user maybe on a different server. [IMPORTANT] ownerUser and/or matchedUser maybe nil if ownerUser and/or matchedUser disconnects from the server.
func SetOnTicketMemberJoined(ticketType uint8, cb func(ticket *Ticket, joinedUser, ownerUser *user.User, memberIDs []string)) bool
SetOnTicketMemberJoined assigns a callback to be invoked when a matched member joins.
[CRITICALLY IMPORTANT] Using pointer variables that are defined outside of the callback closure in the callback closure will cause those pointers to be not garbage collected leading to memory leak. [IMPORTANT] The callback is invoked for the owner user only. [IMPORTANT] joinedUser is a copy of the actual user data of *user.User because the matched user maybe on a different server. [IMPORTANT] ownerUser and/or joinedUser maybe nil if ownerUser and/or joinedUser disconnects from the server.
Parameters
ticketType - Ticket type is used to group tickets. It will assign the callback to the given ticket type. cb - Callback to be invoked when a matched member joins the match.
func SetOnTicketMemberJoinedAnnounce(ticketType uint8, cb func(ticket *Ticket, joinedUser, ownerUser *user.User, memberIDs []string) (ver uint8, cmd uint16, message []byte)) bool
SetOnTicketMemberJoinedAnnounce assigns a callback to be invoked when a matched member joins and returns ver, cmd, and message to be used as an announcement.
An announcement is sent to all matched users.
[CRITICALLY IMPORTANT] Using pointer variables that are defined outside of the callback closure in the callback closure will cause those pointers to be not garbage collected leading to memory leak. [IMPORTANT] The event is invoked for the owner of the ticket only.
Parameters
ticketType - Apply the callback to the given ticket type. cb - Callback to be invoked when a new user successfully match and join. ticket - The matchmaking ticket. joinedUser - The user that joined the matchmaking. [IMPORTANT] This is a copy data of the joined user and it is not the actual joined user data. ownerUser - The owner user of the matchmaking ticket. memberIDs - an array of matched member user IDs.
Example:
added := matching.SetOnTicketMemberJoinedAnnounce(ticketType, func(ticket *matching.Ticket, joinedUser, ownerUser *user.User, memberIDs []string) (ver uint8, cmd uint16, message []byte) { // we will be sending a notification message to all matched users with the following: ver = uint8(2) // the notification message will be sent with command ver 2 cmd = uint16(1010) // the notification message will be sent with command ID 1010 message = []byte(strings.Join(messageIDs, ",")) // the notification message will send a message with comma separated list of matched member user IDs. return ver, cmd, message }) if !added { // failed to assign the callback... }
func SetOnTicketMemberLeave(ticketType uint8, cb func(ticket *Ticket, leftUserData, ownerUser *user.User, roomID string, memberIDs []string)) bool
SetOnTicketMemberLeave assigns a callback to be invoked when a matched member leaves.
[CRITICALLY IMPORTANT] Using pointer variables that are defined outside of the callback closure in the callback closure will cause those pointers to be not garbage collected leading to memory leak. [IMPORTANT] The callback is invoked for the owner user only. [IMPORTANT] leftUser is a copy of the actual user data of *user.User because the matched user maybe on a different server. [IMPORTANT] ownerUser and/or leftUserData maybe nil if ownerUser and/or leftUserData disconnects from the server.
Parameters
ticketType - Ticket type is used to group tickets. It will assign the callback to the given ticket type. cb - Callback to be invoked when a matched member leaves the match.
func SetOnTicketMemberLeaveAnnounce(ticketType uint8, cb func(ticket *Ticket, leftUser, ownerUser *user.User, memberIDs []string) (ver uint8, cmd uint16, message []byte)) bool
SetOnTicketMemberLeaveAnnounce assigns a callback to be invoked when a matched member leaves and returns ver, cmd, and message to be used as an announcement.
An announcement is sent to all matched users.
[CRITICALLY IMPORTANT] Using pointer variables that are defined outside of the callback closure in the callback closure will cause those pointers to be not garbage collected leading to memory leak. [IMPORTANT] The event is invoked for the owner of the ticket only.
Parameters
ticketType - Apply the callback to the given ticket type. cb - Callback to be invoked when a matched user leaves. ticket - The matchmaking ticket. leftUser - The user that left the matchmaking. [IMPORTANT] This is a copy of the left user data and it is not the actual left user data. ownerUser - The owner user of the matchmaking ticket. memberIDs - an array of matched member user IDs.
Example:
added := matching.SetOnTicketMemberLeaveAnnounce(ticketType, func(ticket *matching.Ticket, leftUser, ownerUser *user.User, memberIDs []string) (ver uint8, cmd uint16, message []byte) { // we will be sending a notification message to all matched users with the following: ver = uint8(2) // the notification message will be sent with command ver 2 cmd = uint16(1010) // the notification message will be sent with command ID 1010 message = []byte(strings.Join(messageIDs, ",")) // the notification message will send a message with comma separated list of matched member user IDs. return ver, cmd, message }) if !added { // failed to assign the callback... }
func SetOnTicketTimeout(ticketType uint8, cb func(owner *user.User)) bool
SetOnTicketTimeout assigns a callback to be invoked when an issued ticket has timed out.
[CRITICALLY IMPORTANT] Using pointer variables that are defined outside of the callback closure in the callback closure will cause those pointers to be not garbage collected leading to memory leak. [IMPORTANT] The callback is invoked for the owner user of the ticket only. [IMPORTANT] Owner maybe nil if owner disconnects from the server.
Parameters
ticketType - Ticket type is used to group tickets. It will assign the callback to the given ticket type. cb - Callback to be invoked when a ticket times out.
func SetTicketProperties(ticketType uint8, userData *user.User, data map[string]interface{}) error
SetTicketProperties stores a collection of keys and their values to ticket as properties.
Error Cases
┌────────────────┬────────────────────────────────────────────────────────────────┐ │ Error │ Reason │ ╞════════════════╪════════════════════════════════════════════════════════════════╡ │ Room not found │ MatchMaker ticket is corrupt. │ │ Must be owner │ Only the ticket owner user is allowed to execute the function. │ └────────────────┴────────────────────────────────────────────────────────────────┘ [IMPORTANT] This function is available ONLY for the owner of the ticket. [IMPORTANT] If the same key exists, it overwrites the existing value of the same key. [NOTE] Uses mutex lock internally.
Properties are only primitive values and does not support reference type data such as array and map.
func SetTicketProperty(ticketType uint8, userData *user.User, key string, value interface{}) error
SetTicketProperty stores a key and a value as a property to the ticket.
Error Cases
┌────────────────┬────────────────────────────────────────────────────────────────┐ │ Error │ Reason │ ╞════════════════╪════════════════════════════════════════════════════════════════╡ │ Room not found │ MatchMaker ticket is corrupt. │ │ Must be owner │ Only the ticket owner user is allowed to execute the function. │ └────────────────┴────────────────────────────────────────────────────────────────┘ [IMPORTANT] This function is available ONLY for the owner of the ticket. [NOTE] Uses mutex lock internally.
If the same key exists, it overwrites the existing value of the same key.
Properties are only primitive values and does not support reference type data such as array and map.
func SetTicketPropertyIfNotExists(ticketType uint8, userData *user.User, key string, value interface{}) bool
SetTicketPropertyIfNotExists stores a key and a value as a property to the ticket if the same key does not exist.
[IMPORTANT] This function is available ONLY for the owner of the ticket. [NOTE] Uses mutex lock internally.
Properties are only primitive values and does not support reference type data such as array and map.
func Setup(confpath string)
Setup sets up MatchMaker on the server. You must call this at the start of the server process.
confpath - Absolute path of the configuration file to be loaded.
func StartTicket(ticketType uint8, userData *user.User) error
StartTicket creates and starts a new ticket-based matchmaking with the given ticket type.
[IMPORTANT] If the owner user (user that created the ticket) disconnects or re-connects, the ticket will be canceled automatically. This also means that if you use Diarkis modules (Diarkis Field and Diarkis Room) that may require the user to re-connect such as Room and Field, it may cause the ticket to be canceled unexpected when the user re-connects. [IMPORTANT] Complex search properties with large number of properties with long range (lengthy array of values) may have negative impact on server performance. [NOTE] Uses mutex lock internally.
Error Cases
╒════════════════════════════════════════════════════╤════════════════════════════════════════════════════════════════════════════════╕ │ Error │ Reason │ ╞════════════════════════════════════════════════════╪════════════════════════════════════════════════════════════════════════════════╡ │ MatchMaker is not setup correctly │ SetOnIssueTicket callback for the ticketType must be assigned. │ ├────────────────────────────────────────────────────┼────────────────────────────────────────────────────────────────────────────────┤ │ MatchMaker ticket cannot be issued more than once │ The user is not allowed to issue more than one ticket of the same ticket type. │ ├────────────────────────────────────────────────────┼────────────────────────────────────────────────────────────────────────────────┤ │ Failed to create a ticket │ Given nil for *TicketParams. │ ├────────────────────────────────────────────────────┼────────────────────────────────────────────────────────────────────────────────┤ │ Failed to issue a new ticket │ The user is still in a previous matchmaking room of the same ticket type. │ ╘════════════════════════════════════════════════════╧════════════════════════════════════════════════════════════════════════════════╛
Parameters
ticketType - Ticket type is used to group tickets. You may issue multiple tickets of different ticket types. userData - The user that issues and starts the ticket and becomes the owner of the ticket.
Ticket manages MatchMaker's Add and Search internally, so that you do not have to manage and balance their calls.
Ticket has two phases: "Search" and "Waiting"
Ticket starts out in "Search" phase and moves to "Waiting" phase.
The diagram below shows how a ticket operations internally:
┌──────────────┐ │ Start Ticket │ └──────┬───────┘ │ ▼ ┌──────────────┐ │ Search │ └──────┬───────┘ │ ┌──────────┴──────────┐ │ │ Ticket actively searches for ▼ ▼ other tickets that are ┌───────────────┐ ┌────────┐ Ticket creates a waiting room for in "Wait" phase to match │ Found Matches │ │ Wait │ the ticket and waits for └──────┬────────┘ └──┬──┬──┘ other tickets to "Search" it and match ╭────────────────────────────────────╮ │ │ │ │ Ticket found other tickets │ └────────┐ ┌──────┘ └──────────┐ │ to join and matched ticket ├──────────▷│ │◁──────────┐ │ │ met the required number of users │ │ │ │ │ ╰────────────────────────────────────╯ ▼ ▼ │ ▼ ╔═══════════════════════╗ │ ┌─────────┐ If required number of users are not met ║ Matchmaking Completed ║ │ │ Timeout │ and ticket duration expires, ╚═══════════════════════╝ │ └─────────┘ the ticket times out. In order to continue, ┌──────────┘ The user must issue and start a new ticket │ ╭──────────────────────────────────────────────────┴─╮ │ Other tickets searched and found the ticket │ │ and the required number of users have been matched │ ╰────────────────────────────────────────────────────╯
Diagram below visually explains how these two phases of a ticket work and how some of the parameters affect these two phases.
▶︎ SearchInterval 200ms ▶︎ SearchTries 10 ▶︎ TicketDuration 4s ▷ Search Phase: The ticket will search every 200ms 10 times ▷ Wait Phase: If the ticket does not find match, it will wait for the remainder of time until the ticket duration expires 200ms x 10 searches ┌────── Search Phase ──────┐ ┌─────── Waiting Phase ───────┐ ┌──┬──┬──┬──┬──┬──┬──┬──┬──┬──┰────────────────────────────────┐ │ │ │ │ │ │ │ │ │ │ ┃ │ └──┴──┴──┴──┴──┴──┴──┴──┴──┴──┸────────────────────────────────┘ Total 2 seconds of searching Total 2 seconds of waiting │ │ └─────────── Ticket duration is 4 seconds in total ────────────┘ This means that a ticket in search phase will only match with tickets in wait phase and vice versa.
The table below explains the notifications that the client receives from the server.
┌───────────────────┬──────────────────┬─────────────────┬───────────────────────────────────────────────────────────────────────────┐ │ Notification Type │ Push Command Ver │ Push Command ID │ Description │ ╞═══════════════════╪══════════════════╪═════════════════╪═══════════════════════════════════════════════════════════════════════════╡ │ Success │ 1 │ 220 │ Matchmaking ticket has been successfully completed │ │ │ │ │ and all matched user clients receive this server push. │ ├───────────────────┼──────────────────┼─────────────────┼───────────────────────────────────────────────────────────────────────────┤ │ Timeout │ 1 │ 219 │ Matchmaking ticket has failed and it has been discarded. │ │ │ │ │ All user clients that matched receives this server push. │ ├───────────────────┼──────────────────┼─────────────────┼───────────────────────────────────────────────────────────────────────────┤ │ Cancel │ 1 │ 222 │ Matchmaking ticket has been canceled │ │ │ │ │ and all user clients that matched receives this server push. │ ├───────────────────┼──────────────────┼─────────────────┼───────────────────────────────────────────────────────────────────────────┤ │ Broadcast │ 1 │ 224 │ Matchmaking ticket sends a broadcast message to all matched user clients. │ └───────────────────┴──────────────────┴─────────────────┴───────────────────────────────────────────────────────────────────────────┘
Calling StartTicket raises The callback assigned by SetOnIssueTicket and a new ticket will be created using the given ticket parameters.
Example with SetOnIssueTicket callback
// the callback will be invoked by matching.StartTicket matching.SetOnIssueTicket(sampleTicketType, func(userData *user.User) *matching.TicketParams { return &matching.TicketParams{ ProfileIDs: []string{"RankMatch"}, MaxMembers: 2, SearchInterval: 300, // 300 milliseconds interval of search SearchTries: 4, // allow 4 consecutive empty search results up to 4 times before moving on to wait TicketDuration: 20, // ticket lasts for 20 seconds HowMany: 20, // up to 20 search results Tag: "", // if we want to group tickets using tag add the string value here AddProperties: &map[string]int{ "Rank": 3 }, // wait for other users to find me and my rank is 3 SearchProperties: &map[string][]int{ "Rank": &[]int{ 1, 2, 3, 4, 5 } }, // search for other users within the range of 1 to 5 and property is "Rank" } }) err := matching.StartTicket(sampleTicketType, userData) if err != nil { // error... }
▶︎ SearchPropeties
ServerProperties dictate conditions for searches that is performed internally.
[IMPORTANT] The number of allowed range properties is limited to two. When you have multiple elements in a search property, it is considered as a range property. [IMPORTANT] SearchProperties operates AND operations. It means that with multiple search properties, the search must satisfy all search properties in order to match.
Diagram below shows how each search property operates:
┏━━━┓ ┃ 8 ┃ 8 with ±3 would fall into 5 ~ 11 and that means it matches with items in the bucket of 0 to 10 and 11 to 20 ┗━┳━┛ ┏━┻━━━━┓ │ ▼ │ ▼ │ │ │ 0 ~ 10 │ 11 ~ 20 │ 21 ~ 30 │ └─────────┴─────────┴─────────┘
Example:
searchProps["level"] = []int{ 1, 2, 3, 4, 5 } // range property searchProps["rank"] = []int{ 1, 2, 3 } // range property searchProps["matchType"] = []int{ 1 } // regular property searchProps["league"] = []int{ 10 } // regular property
Order of range search property's search:
The range search properties will look for matches in the order of the array. It means that if []int{ 1, 2, 3, 4, 5 } is given, it will start from 1 and continue up to 5 until it finds it matches.
▶︎ Callbacks
Every callback is assigned to given ticket type and invoked based on assigned ticket type.
func StartTicketBackfill(ticketType uint8, owner *user.User) error
StartTicketBackfill starts "backfill" on a ticket that has already been completed.
Backfill allows other users to match and join "after" the completion of the ticket.
When ticket is completed, the ticket itself will be deleted, but the matched users remain in the ticket room.
The owner user that wishes to start backfill must be a member of this ticket room.
[IMPORTANT] If the ticket is full, no users may match and join even with backfill started. [IMPORTANT] In order to stop backfill, you must invoke StopTicketBackfill. [NOTE] Uses mutex lock internally.
Error Cases
┌────────────────────────────────────────────────────┬────────────────────────────────────────────────────────────────────────────────┐ │ Error │ Reason │ ╞════════════════════════════════════════════════════╪════════════════════════════════════════════════════════════════════════════════╡ │ Completed ticket room must be available │ The ticket and its internal room have been discarded. │ │ Ticket already exists │ Either the ticket has not been completed or backfill has already been started. │ │ MatchMaker is not setup correctly │ SetOnIssueTicket callback for the ticketType must be assigned. │ │ MatchMaker ticket cannot be issued more than once │ The user is not allowed to issue more than one ticket of the same ticket type. │ │ Failed to create a ticket │ Given nil for *TicketParams. │ │ Failed to issue a new ticket │ The user is still in a previous matchmaking room of the same ticket type. │ └────────────────────────────────────────────────────┴────────────────────────────────────────────────────────────────────────────────┘
Parameters
ticketType - Type of the completed ticket to start backfill. owner - Ticket's owner user.
func StopTicketBackfill(ticketType uint8, owner *user.User) error
StopTicketBackfill stops backfill ticket.
[NOTE] Uses mutex lock internally. Error Cases ┌────────────────────────────────┬─────────────────────────────────────────────────────────────────────────┐ │ Error │ Reason │ ╞════════════════════════════════╪═════════════════════════════════════════════════════════════════════════╡ │ Backfill ticket not found │ Backfill ticket to stop does not exist. │ │ Backfill ticket room not found │ Backfill ticket room has been discarded. (All users have disconnected.) │ └────────────────────────────────┴─────────────────────────────────────────────────────────────────────────┘
Parameters
ticketType - Backfill ticket type to stop backfill. owner - Backfill ticket owner user.
func TTLTest(src []int64) []int64
TTLTest this is used ONLY in tests
func Test(method string, data map[string]interface{}) ([]byte, error)
Test this is used ONLY in tests
func TestDebugDataDump() map[string][]*searchItem
TestDebugDataDump is used ONLY in internal tests.
func TicketBroadcast(ticketType uint8, userData *user.User, ver uint8, cmd uint16, msg []byte) error
TicketBroadcast sends a reliable message to all matched users with the given ver, cmd, and message byte array.
[NOTE] This function can be executed by any matched member user. [NOTE] Uses mutex lock internally.
Parameters
ticketType - MatchMaker Ticket's type. userData - Matched member user of the ticket. ver - Broadcast message command version. cmd - Broadcast message command ID. msg - Broadcast message data in byte array format.
func UpdateTicketProperties( ticketType uint8, userData *user.User, data map[string]interface{}, cb func(exists bool, storedValue interface{}, newValue interface{}) (updateValue interface{})) error
UpdateTicketProperties changes the existing property values of ticket.
The callback is invoked while the internal lock is still held, locking inside the callback may cause mutex deadlock.
Error Cases
┌────────────────┬────────────────────────────────────────────────────────────────┐ │ Error │ Reason │ ╞════════════════╪════════════════════════════════════════════════════════════════╡ │ Room not found │ MatchMaker ticket is corrupt. │ │ Must be owner │ Only the ticket owner user is allowed to execute the function. │ └────────────────┴────────────────────────────────────────────────────────────────┘
Highlights
[IMPORTANT] This function is available ONLY for the owner of the ticket. [IMPORTANT] This function is NOT asynchronous. [IMPORTANT] Properties are only primitive values and does not support reference type data such as array and map. [NOTE] Uses mutex lock internally. [NOTE] The callback is invoked while the lock is still being held. Avoid using locks in the callback to prevent mutex deadlocks.
Parameters
ticketType - Ticket type is used to find the ticket. userData - Owner user data of the ticket. data - A map of key and value pair to be stored or updated as properties. cb - Callback to be invoked on every key and value pair to handle the update. func(exists bool, storedValue interface{}, updateValue interface{}) (updatedValue interface{}) - exists - Indicates if the same key already exists or not - storedValue - Existing value that is stored as a property. If the key does not exist it is a nil. - updateValue - The value to be used to update/replace or set.
func UpdateTicketProperty( ticketType uint8, userData *user.User, key string, value interface{}, cb func(exists bool, storedValue interface{}, newValue interface{}) (updateValue interface{})) error
UpdateTicketProperty changes the existing property value of ticket.
Error Cases
┌────────────────┬────────────────────────────────────────────────────────────────┐ │ Error │ Reason │ ╞════════════════╪════════════════════════════════════════════════════════════════╡ │ Room not found │ MatchMaker ticket is corrupt. │ │ Must be owner │ Only the ticket owner user is allowed to execute the function. │ └────────────────┴────────────────────────────────────────────────────────────────┘
Highlights
[IMPORTANT] This function is available ONLY for the owner of the ticket. [IMPORTANT] This function is NOT asynchronous. [IMPORTANT] Properties are only primitive values and does not support reference type data such as array and map. [NOTE] Uses mutex lock internally. [NOTE] The callback is invoked while the lock is still being held. Avoid using locks in the callback to prevent mutex deadlocks.
Parameters
ticketType - Ticket type is used to find the ticket. userData - Owner user data of the ticket. key - A key of the property to be updated. value - A value of the property to be updated with. cb - Callback to be invoked on every key and value pair to handle the update. func(exists bool, storedValue interface{}, updateValue interface{}) (updatedValue interface{}) - exists - Indicates if the same key already exists or not - storedValue - Existing value that is stored as a property. If the key does not exist it is a nil. - updateValue - The value to be used to update/replace or set.
AddData represents internally used matchmaking data
type AddData struct { InternalID string `json:"internalID"` MatchingID string `json:"matchingID"` Tag string `json:"tag"` Props map[string]int `json:"props"` Value map[string]interface{} `json:"value"` TTL int64 `json:"ttl"` }
Client represents matchmaking ticket matched member user client.
type Client struct { ID string SID string // Available ONLY for UDP PublicAddress string // Available ONLY for UDP PrivateAddressBytes []byte // User property data copied when the user joins a matchmaking ticket UserData map[string]interface{} }
func GetTicketMemberClients(ticketType uint8, userData *user.User) ([]*Client, bool)
GetTicketMemberClients returns the list of matched member user clients.
Cases for the second return value to be false
Highlights
[IMPORTANT] This function is available ONLY for the owner of the ticket. [IMPORTANT] If non-user uses this function it returns an empty array. [NOTE] Uses mutex lock internally.
FindOwnerData represents internally used data
type FindOwnerData struct { SID string `json:"sid"` }
JoinRoomData represents internally used data
type JoinRoomData struct { TicketType uint8 `json:"ticketType"` ID string `json:"id"` SID string `json:"sid"` MeshAddr string `json:"meshAddr"` UserData map[string]interface{} `json:"userData"` }
LeaveRoomData represents internally used data
type LeaveRoomData struct { TicketType uint8 `json:"ticketType"` ID string `json:"id"` UID string `json:"uid"` SID string `json:"sid"` }
PartialRemoveData represents internally used matchmaking removal data
type PartialRemoveData struct { MatchingID string `json:"m"` UniqueIDs []string `json:"u"` Tags []string `json:"t"` }
RemoveData represents internally used matchmaking removal data
type RemoveData struct { MatchingID string `json:"matchingID"` UniqueIDs []string `json:"uniqueIDs"` }
Room represents matchmaker ticket room that is used internally
type Room struct { sync.RWMutex // contains filtered or unexported fields }
func (r *Room) CancelReservation(userData *user.User) bool
CancelReservation removes the reservation of the given user from the ticket room.
[NOTE] Uses mutex lock internally.
func (r *Room) GetID() string
GetID returns the room ID.
func (r *Room) GetMemberIDs() []string
GetMemberIDs returns an array of matched member IDs.
[NOTE] Uses mutex lock internally.
func (r *Room) GetMemberMeshAddrByUID(uid string) string
GetMemberMeshAddrByUID returns a mesh address of a member.
Returns an empty string if the member is not found or invalid.
[NOTE] Uses mutex lock internally.
func (r *Room) GetMemberMeshAddrList() []string
GetMemberMeshAddrList returns an array of internal server address of each matched user.
[NOTE] Uses mutex lock internally.
func (r *Room) GetMemberSIDByUID(uid string) string
GetMemberSIDByUID returns the member's SID.
It returns and empty string if the member is not found or invalid.
[NOTE] Uses mutex lock internally.
func (r *Room) GetMemberSIDs() []string
GetMemberSIDs returns an array of matched member SIDs.
[NOTE] Uses mutex lock internally.
func (r *Room) GetMemberUsers() []*user.User
GetMemberUsers returns an array of matched member user copies.
[IMPORTANT] The return array contains copies of member users. [NOTE] Uses mutex lock internally.
func (r *Room) GetOwnerUser() (*user.User, bool)
GetOwnerUser returns the ticket owner user.
[IMPORTANT] Returned owner user is NOT a copy. [NOTE] Uses mutex lock internally.
func (r *Room) GetProperties(keys []string) map[string]interface{}
GetProperties returns key and value pairs as a map.
[NOTE] Properties are only primitive values and does not support reference type data such as array and map. [NOTE] Uses mutex lock internally.
If a value of a given key does not exist, the returned map will have a nil as a value of the key.
The returned property value is an interface{}, in order to type assert safely, please use Diarkis' util package functions.
Example:
values, ok := r.GetProperties([]string{ "someKey" }) if !ok { // handle error here } for key, v := range values { // If the value data type is an uint8, of course ;) value, ok := util.ToUint8(v) }
func (r *Room) GetProperty(key string) (interface{}, bool)
GetProperty returns the value of the given key and if the key does not exist, the second return value will be a false.
[NOTE] Properties are only primitive values and does not support reference type data such as array and map. [NOTE] Uses mutex lock internally.
The returned property value is an interface{}, in order to type assert safely, please use Diarkis' util package functions.
Example:
v, ok := r.GetProperty("someKey") if !ok { // handle error here } // If the value data type is an uint8, of course ;) v, ok := util.ToUint8(v)
func (r *Room) MakeReservation(userData *user.User) bool
MakeReservation allows the user to reserve a spot in the ticket room.
[NOTE] Uses mutex lock internally.
func (r *Room) SetOnDeleted(cb func(id string)) bool
SetOnDeleted assigns a callback on ticket room deletion.
[NOTE] You may assign multiple callbacks to a room. [NOTE] Uses mutex lock internally.
func (r *Room) SetOnJoin(cb func(id string, userData *user.User) bool) bool
SetOnJoin assigns a callback on ticket room to be invoked when a new member is matched and attempting to join the match.
The callback returns a bool and if you return false, the matched user will be rejected and will not match and join.
[NOTE] You may assign multiple callbacks to a room. [NOTE] Uses mutex lock internally.
func (r *Room) SetOnJoined(cb func(id string, userData *user.User)) bool
SetOnJoined assigns a callback on ticket room to be invoked when a new member is matched.
[NOTE] You may assign multiple callbacks to a room. [NOTE] Uses mutex lock internally.
func (r *Room) SetOnLeft(cb func(id string, userData *user.User)) bool
SetOnLeft assigns a callback on ticket room to be invoked when a member of matched user leaves the match.
[NOTE] You may assign multiple callbacks to a room. [NOTE] Uses mutex lock internally.
func (r *Room) SetOnTick(interval uint16, cb func(id string)) bool
SetOnTick assigns a callback to be invoked at every given interval.
[IMPORTANT] A single callback may be assigned per tick interval. You may not assign multiple callback a tick with the same interval. [NOTE] Uses mutex lock internally.
Parameters
interval - Tick interval in seconds. cb - Callback to be invoked at every tick.
func (r *Room) SetOnTickStop(interval uint16, cb func(id string)) bool
SetOnTickStop assigns a callback to be invoked when a tick of the room stops.
[IMPORTANT] Only one callback may be assigned to a room. [NOTE] Uses mutex lock internally.
func (r *Room) SetProperties(data map[string]interface{})
SetProperties stores a collection of keys and their values to ticket room.
If the same key exists, it overwrites the existing value of the same key.
[NOTE] Properties are only primitive values and does not support reference type data such as array and map. [NOTE] Uses mutex lock internally.
func (r *Room) SetProperty(key string, value interface{})
SetProperty stores a key and value data to ticket room.
If the same key exists, it overwrites the existing value of the same key.
[NOTE] Properties are only primitive values and does not support reference type data such as array and map. [NOTE] Uses mutex lock internally.
func (r *Room) SetPropertyIfNotExists(key string, value interface{}) bool
SetPropertyIfNotExists stores a key and value data to ticket room if the same key does not exist.
[NOTE] Properties are only primitive values and does not support reference type data such as array and map. [NOTE] Uses mutex lock internally.
func (r *Room) StopAllTicks() bool
StopAllTicks stops all tick loops.
[NOTE] Uses mutex lock internally.
func (r *Room) UpdateProperties(data map[string]interface{}, cb func(bool, interface{}, interface{}) interface{})
UpdateProperties changes the existing property values of ticket room.
The callback is invoked while the internal lock is still held, locking inside the callback may cause mutex deadlock.
[NOTE] Properties are only primitive values and does not support reference type data such as array and map. [NOTE] Uses mutex lock internally.
Parameters
data - A map of key and value pair to be stored as properties. cb - Callback to be invoked on every key and value pair to handle the update. func(exists bool, storedValue interface{}, updateValue interface{}) (updatedValue interface{}) - exists - Indicates if the same key already exists or not - storedValue - Existing value that is stored as a property. If the key does not exist it is a nil. - updateValue - The value to be used to update/replace or set.
func (r *Room) UpdateProperty(key string, value interface{}, cb func(bool, interface{}, interface{}) interface{})
UpdateProperty changes the existing property value of ticket room.
The callback is invoked while the internal lock is still held, locking inside the callback may cause mutex deadlock.
[NOTE] Properties are only primitive values and does not support reference type data such as array and map.
[NOTE] Uses mutex lock internally.
Parameters
key - A key of the property to be updated. value - A value of the property to be updated with. cb - Callback to be invoked on every key and value pair to handle the update. func(exists bool, storedValue interface{}, updateValue interface{}) (updatedValue interface{}) - exists - Indicates if the same key already exists or not - storedValue - Existing value that is stored as a property. If the key does not exist it is a nil. - updateValue - The value to be used to update/replace or set.
RoomBroadcastData represents internally used broadcast message data
type RoomBroadcastData struct { ID string `json:"id"` Ver uint8 `json:"ver"` Cmd uint16 `json:"cmd"` Msg []byte `json:"msg"` MemberSIDs []string `json:"memberSIDs"` }
RoomJoinReturnData represents internally used data
type RoomJoinReturnData struct { LockKey string `json:"lockKey"` }
SearchData represents internally used matchmaking data
type SearchData struct { MatchingID string `json:"matchingID"` Tag string `json:"tag"` Props map[string][]int `json:"props"` Limit int `json:"limit"` }
SearchReturnData represents internally used data
type SearchReturnData struct { Results []*SearchReturnItemData `json:"results"` }
SearchReturnItemData represents internally used data
type SearchReturnItemData struct { ID string `json:"id"` TTL int64 `json:"ttl"` Value interface{} `json:"value"` }
Ticket represents a matchmaking ticket that manages a life cycle of issued ticket
OnMatch - Raised when a remote user matches. By returning true, you may complete the ticket and raise OnComplete (OnComplete event is captured by matching.SetOnComplete callback) OnMatchedMemberJoined - Raised when a matched member completes join. OnMatchedMemberJoinedAnnounce - Raised when a matched member completes join and returns ver, cmd, and message to be sent to all matched members. OnMatchedMemberLeaveAnnounce - Raised when a matched member leaves and returns ver, cmd, and message to be sent to all matched members. OnMatchedMemberLeave - Raised when a matched member user leave the match. OnTimeout - Raised when the ticket times out.
type Ticket struct { OnMatch func(ticket *Ticket, userData *user.User, owner *user.User, roomID string, memberIDs []string) bool OnMatchedMemberJoined func(ticket *Ticket, userData *user.User, owner *user.User, memberIDs []string) OnMatchedMemberLeave func(ticket *Ticket, userData *user.User, owner *user.User, roomID string, memberIDs []string) OnTimeout func(userData *user.User) OnMatchedMemberJoinedAnnounce func(ticket *Ticket, userData, owner *user.User, memberIDs []string) (ver uint8, cmd uint16, message []byte) OnMatchedMemberLeaveAnnounce func(ticket *Ticket, userData, owner *user.User, memberIDs []string) (ver uint8, cmd uint16, message []byte) // contains filtered or unexported fields }
func FindTicket(ticketType uint8, userData *user.User) *Ticket
FindTicket returns the valid matchmaking ticket that the user has.
[IMPORTANT] This function works with the owner of the ticket only. [IMPORTANT] IF the user given does not own a ticket, it returns nil. [NOTE] Uses mutex lock internally. ticketType - MatchMaker ticket type. userData - The owner user of the ticket.
func (t *Ticket) GetRoomID() string
GetRoomID returns the room ID of the ticket.
func (t *Ticket) GetTicketType() uint8
GetTicketType returns the ticket type of the *Ticket instance.
func (t *Ticket) IsTicketFinished() bool
IsTicketFinished returns true if the ticket has finished its entire operations.
func (t *Ticket) Start() bool
Start starts the life cycle of a ticket.
[NOTE] Uses mutex lock internally.
func (t *Ticket) Stop() bool
Stop interrupts the ticket and stops all matchmaking operations.
[NOTE] Uses mutex lock internally.
TicketHolder represents add and search properties of the ticket holder user.
AddProperties - Add properties of the ticket: Add properties are used to be found by other tickets. SearchProperties - Search properties of the ticket: Search properties are used to search for other tickets. ApplicationData - May hold byte array encoded application data that maybe added from the application.
type TicketHolder struct { AddProperties map[string]int SearchProperties map[string][]int ApplicationData []byte }
TicketParams parameter struct for issueTicket
[IMPORTANT] AddProperties and SearchProperties are limited to have up to 2 properties.
Properties
ProfileIDs - A list of profiles to add to and search against. AddProfileIDs - Optional list of profiles to add. If this is used, ProfileIDs will be overridden for add. SearchProfileIDs - Optional list of profiles to search. If this is used, ProfileIDs will be overridden for search. Tag - A string tag to group matchmaking data by the same tag. Data with different tag do NOT match even with the matching properties. Leave it with an empty string if no need. AddProperties - Matchmaking properties (conditions) for add (being a host waiting) SearchProperties - Matchmaking properties to used for search Each property may contain a range of property values i.e. []int{ 1, 2, 3, 4, 5 } etc. The number of properties allowed is 2, if you exceed the number of properties, two properties will be randomly chosen. ApplicationData - May hold application data that maybe added from the application. ApplicationData must NOT be a struct or must NOT contain struct. MaxMembers - Maximum number of matchmaking users per matchmaking. When matched users reach this number, the matchmaking will complete as success TicketDuration - Duration of the ticket to be valid in seconds. Minimum value for TicketDuration is 10 seconds. SearchInterval - The interval for search in milliseconds TimeoutExtensionOnMatchJoin - Timeout extension in seconds to be added every time a new match joins. Leave it with 0 if no need. SearchTries - Number of empty search results to tolerate before giving up and moving on to hosting (add) EmptySearches - If the number of empty search results reach EmptySearches, the ticket will forcefully change to add phase. If 0 is given, this feature will be disabled. Default is 0. HowMany - Matchmaking profile IDs to use for search and add Leave this empty if you do not need to repeat the operation set.
A ticket has two phases. When you start a ticket, it starts as a search phase where it actively searches other tickets that are in waiting phase. Once a certain time passes and the search yields no matches, ticket then switches to waiting phase where it waits for other searching tickets to find it.
Diagram below visually explains how these two phases of a ticket work and how some of the parameters affect these two phases.
▶︎ SearchInterval 200ms ▶︎ SearchTries 10 ▶︎ TicketDuration 4s ▷ Search Phase: The ticket will search every 200ms 10 times ▷ Wait Phase: If the ticket does not find match, it will wait for the remainder of time until the ticket duration expires 200ms x 10 searches ┌────── Search Phase ──────┐ ┌─────── Waiting Phase ───────┐ ┌──┬──┬──┬──┬──┬──┬──┬──┬──┬──┰────────────────────────────────┐ │ │ │ │ │ │ │ │ │ │ ┃ │ └──┴──┴──┴──┴──┴──┴──┴──┴──┴──┸────────────────────────────────┘ Total 2 seconds of searching Total 2 seconds of waiting │ │ └─────────── Ticket duration is 4 seconds in total ────────────┘ This means that a ticket in search phase will only match with tickets in wait phase and vice versa.
It usually helps to have randomized values for SearchInterval, SearchTries, and TicketDuration.
This is because every ticket strictly follows search → wait flow. Having every ticket with different search and wait durations will help tickets find other tickets.
type TicketParams struct { ProfileIDs []string AddProfileIDs []string SearchProfileIDs []string Tags []string AddProperties map[string]int SearchProperties map[string][]int ApplicationData []byte MaxMembers uint8 TicketDuration uint8 SearchInterval uint16 TimeoutExtensionOnMatchJoin uint8 SearchTries uint8 EmptySearches uint8 HowMany uint8 }
TicketProperties represents both the owner of the matched ticket and the candidate to be matched.
It is primarily meant to be used for SetOnTicketAllowMatchIf callback.
Owner - Represents ticket owner's add and search properties (user that perform add/waiting). Owner add and search properties are pointers to the original properties and changing the values may influence the matchmaking. Candidates - A map of match candidate's add and search properties (user that performs searches) by candidate's UID as keys. Candidate add and search properties are pointers to the original properties and changing the values may influence the matchmaking.
type TicketProperties struct { sync.RWMutex // contains filtered or unexported fields }
func (t *TicketProperties) GetAllCandidates() map[string]*TicketHolder
GetAllCandidates returns all candidates' *TicketHolder instances as a map. The key of the map is UID.
[NOTE] Returned map of *TicketHolder is a copy of the actual candidate ticket holders.
func (t *TicketProperties) GetCandidateByUID(uid string) (*TicketHolder, bool)
GetCandidateByUID returns the given UID's *TicketHolder instance. If the second value is false, there is no candidate that matches the given UID.
[NOTE] Returned *TicketHolder is a copy of the actual candidate ticket holder.
func (t *TicketProperties) GetOwner() *TicketHolder
GetOwner returns the ticket owner's *TicketHolder instance
[NOTE] Returned *TicketHolder is a copy of the actual candidate ticket holder.
UpdateUserData represents internally used user data update
type UpdateUserData struct { RoomID string `json:"id"` UserID string `json:"ID"` SID string `json:"SID"` PublicAddr string `json:"PublicAddr"` PrivateAddrBytes []byte `json:"PrivateAddrBytes"` MeshAddr string `json:"meshAddr"` }