Skip to content

Instantly share code, notes, and snippets.

@kixxauth
Last active August 29, 2015 14:03
Show Gist options
  • Save kixxauth/04f28602cbd889f2220f to your computer and use it in GitHub Desktop.
Save kixxauth/04f28602cbd889f2220f to your computer and use it in GitHub Desktop.
Match Making Psuedo Code
# Overview
# --------
# The Match Making Service is called via a persisted socket connection
# from the Xbox (if possible). It works on an event driven system (event loop)
# rather than a threaded approach. This means we don't have to worry about locks,
# mutexes, and related bad things, but we do need to make sure we keep the
# execution time of the execution stacks in each event loop to a minimum.
#
# Approach
# --------
# - Each connected player has an associated Player object in memory.
# - Each Player object maintains an ordered list of all other connected players.
# - The ordered lists of players are ordered by their distance score from the
# owning player.
# - When a player updates his attributes, the Player object rebuilds the
# ordered list of other players.
# - Also, when a player updates his attributes, the other Player objects
# reposition him in their lists.
# !GLOBAL (cached objects)
playerPool = new PlayerPool()
matchRequests = new MatchRequestHash()
# Events initiated by the XBox Client
# -----------------------------------
# We're assuming these events are being received from the XBox client via a
# websocket connection, and the Player objects passed into these handlers are
# fetched from the Player Identity service based on the player ID from the Xbox
# client and stored in memory here in the Match Making Service.
# Event Handler
# Called when a player connects and starts a new session.
# thisPlayer - The Player object who is connecting.
onPlayerConnection = (thisPlayer) ->
# Add the player to the pool.
playerPool.add(thisPlayer)
# Update the match list ordering for all players in the pool and update the
# clients to inform them of the new lists.
for player in playerPool.all()
if player is thisPlayer
player.rebuildList()
continue
player.spliceToList(thisPlayer)
sendPossibleMatches(player.matchList())
return
# Event Handler
# Called when a player makes a choice that updates their matching attributes.
# thisPlayer - The Player object who is updating.
# limit - The limit to the number of potential matches to find.
onPlayerUpdateAttributes = (thisPlayer) ->
# Update the match list ordering for all players in the pool and update the
# clients to inform them of the new lists.
for player in playerPool.all()
if player is thisPlayer
player.rebuildList()
continue
player.updatePlayer(thisPlayer)
sendPossibleMatches(player.matchList())
return
# Event Handler
# Called when thisPlayer sends a match request to thatPlayer.
# thisPlayer - The Player making the match request.
# thatPlayer - The Player to receive the match request.
onPlayerMatchRequest = (thisPlayer, thatPlayer) ->
# We remove the requesting player from the pool, but allow the target player to
# remain in the active pool.
playerPool.remove(thisPlayer)
# Craete and send the match request.
matchRequest = matchRequests.create(thisPLayer, thatPlayer)
matchRequest.record()
sendMatchRequest(matchRequest)
return
# Event Handler
# Called when thisPlayer denies a match request sent by thatPlayer.
# thisPlayer - The Player denying the match request.
# thatPlayer - The Player who made the match request.
onPlayerDenyRequest = (thisPlayer, thatPlayer) ->
matchRequest = matchRequests.get(thatPlayer, thisPlayer)
# Remove this match request from memory.
matchRequests.remove(matchRequest)
# Notify the client of the denial.
sendRequestDenial(matchRequest)
# Add this player back into the availability pool.
playerPool.add(thatPlayer)
return
# Event Handler
# Called when thisPlayer accepts a match request sent by thatPlayer.
# thisPlayer - The Player accepting the match request.
# thatPlayer - The Player who made the match request.
onPlayerAcceptRequest = (thisPlayer, thatPlayer) ->
# Remove all pending match requests for both players and notify other players
# their pending request has been denied for these two players.
removedRequests = matchRequests.removePlayers(thisPlayer, thatPlayer)
sendRequestDenial(matchRequest) for matchRequest in removedRequests
# Create a new Match instance and send it to both clients.
match = new Match({requester: thatPlayer, target: thisPlayer})
match.record()
sendMatch(match)
return
# Event Handler
# Called when thisPlayer leaves OverDog
onPlayerLeave = (thisPlayer) ->
# Remove this player from the pool
playerPool.remove(thisPlayer)
# Update the match list ordering for all players in the pool and update the
# clients to inform them of the new lists.
for player in playerPool.all()
player.removePlayer(thisPlayer)
sendPossibleMatches(player.matchList())
# Remove all pending match requests for this player and notify other players
# their pending request has been denied for this player.
removedRequests = matchRequests.removePlayers(thisPlayer)
sendRequestDenial(matchRequest) for matchRequest in removedRequests
return
# Response Functions
# ------------------
# We're assuming we have an open websocket connection to the Xbox client of
# each player, and can push notifications back to them.
# Responder
# Called to notify a client of a new list of possible matching players.
sendPossibleMatches = (player, matchingPlayers) ->
# Responder
# Called to notify a target client of a match request.
sendMatchRequest = (matchRequest) ->
# Responder
# Called to notify the client XBox of both players who've been matched.
# match - A Match instance
sendMatch = (match) ->
# Responder
# Called to notify the client XBox that a players match request was denied.
# matchRequest - A MatchRequest instance.
sendRequestDenial = (matchRequest) ->
# Type Classes
# ------------
# For the most part the Matching Engine uses a functional style of program
# development, but we still could use some Type Classes.
# Player Object definition.
# Instances of this class have an internal ordered list of other players to
# match with.
class Player
# Add a player to this player's ordered list of best matches.
spliceToList: (player) ->
# Update this player's ordered list of best matches with an updated player.
updatePlayer: (player) ->
# Update this player's ordered list of best matches when a player drops out.
removePlayer: (player) ->
# Return the ordered match list of other players for this player.
matchList: ->
# A List type class of players available to be matched.
class PlayerPool
add: (player) ->
get: (index) ->
remove: (player) ->
# Returns an Array of all players in the pool.
all: ->
# A Dictionary lookup type class
class MatchRequestHash
# Create a new MatchRequest instance and add it to this Hash.
# requester - The player making the match request.
# target - The player targeted for the match request.
create: (requester, target) ->
# Get a specific match requst.
# requester - The player who made the match request.
# target - The player targeted for the match request.
get: (requester, target) ->
# Remove a specific match request.
remove: (matchRequest) ->
# Remove all match requests for the specified players.
# Returns removed MatchRequest instances.
removePlayers: (players...) ->
# MatchRequest type class
class MatchRequest
constructor: (spec = {}) ->
@requester = spec.requester
@target = spec.target
# Record this MatchRequest for later analysis.
record: ->
# Match type class
class Match
constructor: (spec = {}) ->
@requester = spec.requester
@target = spec.target
# Record this Match for later analysis.
record: ->
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment