/// <inheritdoc/> public IMatchmakerQueueTask <T> EnqueueGroup(EntityGroup <T> entities, EventHandler <MatchmakingStateChangedEventArgs <T> > callback = null) { RankingMatchmakerQueueTask <T> task = new RankingMatchmakerQueueTask <T>(this, entities, callback); QueueGroup queueGroup = new QueueGroup { task = task }; MatchRankingContext <T> context = new MatchRankingContext <T>(DiscardThreshold); //Look at all other entities in queue and rate them lock (queueSnapshot) AddMatchesToQueueGroup(queueGroup, queueSnapshot, context); lock (inQueue) { //Rate those to be added in future AddMatchesToQueueGroup(queueGroup, inQueue, context); //Add to in queue for next tick/flush inQueue.Enqueue(queueGroup); } return(task); }
/// <summary> /// Calculates and adds matches to the given group. /// </summary> /// <param name="group">The group to calculate for.</param> /// <param name="groups">The groups to calculate against.</param> /// <param name="context">The context for the matchmaker.</param> private void AddMatchesToQueueGroup(QueueGroup group, IEnumerable <QueueGroup> groups, MatchRankingContext <T> context) { foreach (QueueGroup other in groups) { float outerAcc = 0; bool failed = false; foreach (T entity in group.task.Entities) { float acc = 0; foreach (T otherEntity in other.task.Entities) { float value = GetSuitabilityMetric(entity, otherEntity, context); //Check individual discard threshold, if not enough ignore the group if (value < DiscardThreshold) { failed = true; break; } acc += value; } //If we've already failed then just skip the reset if (failed) { break; } outerAcc += acc / other.task.Entities.Count; } //Already failed, don't add match if (failed) { continue; } outerAcc /= group.task.Entities.Count; //If a good enough match then add to our list of posible matches if (outerAcc >= GroupDiscardThreshold) { group.matches.AddLast(new Match { other = other, value = outerAcc }); } } }
/// <summary> /// Returns a suitability metric for the given entity pair. /// </summary> /// <param name="entity1">The first entity.</param> /// <param name="entity2">The second entity.</param> /// <param name="context">Additional information about the ranking.</param> /// <returns>A value between 0 and 1 indicating the suitability where 1 is the perfect match for each other and 0 is the worst possible match.</returns> public abstract float GetSuitabilityMetric(T entity1, T entity2, MatchRankingContext <T> context);