Last active
August 29, 2015 14:03
-
-
Save kixxauth/04f28602cbd889f2220f to your computer and use it in GitHub Desktop.
Match Making Psuedo Code
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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