Skip to content

Commit 9b2573b

Browse files
authored
feat(gamelift): add MatchmakingConfiguration L2 Construct for GameLift (#23326)
Following aws/aws-cdk-rfcs#436 I have written the Gamelift QueuedMatchmakingConfiguration and StandaloneMatchmakingConfiguration L2 constructs which create all related resources. ---- ### All Submissions: * [x] Have you followed the guidelines in our [Contributing guide?](https://github.com/aws/aws-cdk/blob/main/CONTRIBUTING.md) ### Adding new Construct Runtime Dependencies: * [ ] This PR adds new construct runtime dependencies following the process described [here](https://github.com/aws/aws-cdk/blob/main/CONTRIBUTING.md/#adding-construct-runtime-dependencies) ### New Features * [x] Have you added the new feature to an [integration test](https://github.com/aws/aws-cdk/blob/main/INTEGRATION_TESTS.md)? * [x] Did you use `yarn integ` to deploy the infrastructure and generate the snapshot (i.e. `yarn integ` without `--dry-run`)? *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
1 parent cbc5f98 commit 9b2573b

31 files changed

+3575
-1
lines changed

packages/@aws-cdk/aws-gamelift/README.md

+38
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,44 @@ configuration or game server fleet management system.
5252

5353
## GameLift FlexMatch
5454

55+
### Defining a Matchmaking configuration
56+
57+
FlexMatch is available both as a GameLift game hosting solution (including
58+
Realtime Servers) and as a standalone matchmaking service. To set up a
59+
FlexMatch matchmaker to process matchmaking requests, you have to create a
60+
matchmaking configuration based on a RuleSet.
61+
62+
More details about matchmaking ruleSet are covered [below](#matchmaking-ruleset).
63+
64+
There is two types of Matchmaking configuration:
65+
66+
Through a game session queue system to let FlexMatch forms matches and uses the specified GameLift queue to start a game session for the match.
67+
68+
```ts
69+
declare const queue: gamelift.GameSessionQueue;
70+
declare const ruleSet: gamelift.MatchmakingRuleSet;
71+
72+
new gamelift.QueuedMatchmakingConfiguration(this, 'QueuedMatchmakingConfiguration', {
73+
matchmakingConfigurationName: 'test-queued-config-name',
74+
gameSessionQueues: [queue],
75+
ruleSet: ruleSet,
76+
});
77+
```
78+
79+
Or through a standalone version to let FlexMatch forms matches and returns match information in an event.
80+
81+
```ts
82+
declare const ruleSet: gamelift.MatchmakingRuleSet;
83+
84+
new gamelift.StandaloneMatchmakingConfiguration(this, 'StandaloneMatchmaking', {
85+
matchmakingConfigurationName: 'test-standalone-config-name',
86+
ruleSet: ruleSet,
87+
});
88+
```
89+
90+
91+
More details about Game session queue are covered [below](#game-session-queue).
92+
5593
### Matchmaking RuleSet
5694

5795
Every FlexMatch matchmaker must have a rule set. The rule set determines the

packages/@aws-cdk/aws-gamelift/lib/index.ts

+3
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ export * from './game-server-group';
66
export * from './ingress-rule';
77
export * from './fleet-base';
88
export * from './build-fleet';
9+
export * from './matchmaking-configuration';
10+
export * from './queued-matchmaking-configuration';
11+
export * from './standalone-matchmaking-configuration';
912
export * from './game-session-queue';
1013
export * from './matchmaking-ruleset';
1114
export * from './matchmaking-ruleset-body';
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,286 @@
1+
import * as cloudwatch from '@aws-cdk/aws-cloudwatch';
2+
import * as sns from '@aws-cdk/aws-sns';
3+
import * as cdk from '@aws-cdk/core';
4+
import { Construct } from 'constructs';
5+
import { IMatchmakingRuleSet } from '.';
6+
7+
/**
8+
* A set of custom properties for a game session, formatted as key-value pairs.
9+
* These properties are passed to a game server process with a request to start a new game session.
10+
*
11+
* This parameter is not used for Standalone FlexMatch mode.
12+
*
13+
* @see https://docs.aws.amazon.com/gamelift/latest/developerguide/gamelift-sdk-server-api.html#gamelift-sdk-server-startsession
14+
*/
15+
export interface GameProperty {
16+
/**
17+
* The game property identifier.
18+
*/
19+
readonly key: string;
20+
/**
21+
* The game property value.
22+
*/
23+
readonly value: string;
24+
}
25+
26+
/**
27+
* Represents a Gamelift matchmaking configuration
28+
*/
29+
export interface IMatchmakingConfiguration extends cdk.IResource {
30+
/**
31+
* The name of the matchmaking configuration.
32+
*
33+
* @attribute
34+
*/
35+
readonly matchmakingConfigurationName: string;
36+
37+
/**
38+
* The ARN of the matchmaking configuration.
39+
*
40+
* @attribute
41+
*/
42+
readonly matchmakingConfigurationArn: string;
43+
44+
/**
45+
* The notification target for matchmaking events
46+
*
47+
* @attribute
48+
*/
49+
readonly notificationTarget?: sns.ITopic;
50+
51+
52+
/**
53+
* Return the given named metric for this matchmaking configuration.
54+
*/
55+
metric(metricName: string, props?: cloudwatch.MetricOptions): cloudwatch.Metric;
56+
57+
/**
58+
* Matchmaking requests currently being processed or waiting to be processed.
59+
*/
60+
metricCurrentTickets(props?: cloudwatch.MetricOptions): cloudwatch.Metric;
61+
62+
/**
63+
* For matchmaking configurations that require acceptance, the potential matches that were accepted since the last report.
64+
*/
65+
metricMatchesAccepted(props?: cloudwatch.MetricOptions): cloudwatch.Metric;
66+
67+
/**
68+
* Potential matches that were created since the last report.
69+
*/
70+
metricMatchesCreated(props?: cloudwatch.MetricOptions): cloudwatch.Metric;
71+
72+
/**
73+
* Matches that were successfully placed into a game session since the last report.
74+
*/
75+
metricMatchesPlaced(props?: cloudwatch.MetricOptions): cloudwatch.Metric;
76+
77+
/**
78+
* For matchmaking configurations that require acceptance, the potential matches that were rejected by at least one player since the last report.
79+
*/
80+
metricMatchesRejected(props?: cloudwatch.MetricOptions): cloudwatch.Metric;
81+
82+
/**
83+
* Players in matchmaking tickets that were added since the last report.
84+
*/
85+
metricPlayersStarted(props?: cloudwatch.MetricOptions): cloudwatch.Metric;
86+
87+
/**
88+
* For matchmaking requests that were put into a potential match before the last report,
89+
* the amount of time between ticket creation and potential match creation.
90+
*
91+
* Units: seconds
92+
*/
93+
metricTimeToMatch(props?: cloudwatch.MetricOptions): cloudwatch.Metric;
94+
}
95+
96+
/**
97+
* A full specification of a matchmaking configuration that can be used to import it fluently into the CDK application.
98+
*/
99+
export interface MatchmakingConfigurationAttributes {
100+
/**
101+
* The ARN of the Matchmaking configuration
102+
*
103+
* At least one of `matchmakingConfigurationArn` and `matchmakingConfigurationName` must be provided.
104+
*
105+
* @default derived from `matchmakingConfigurationName`.
106+
*/
107+
readonly matchmakingConfigurationArn?: string;
108+
109+
/**
110+
* The identifier of the Matchmaking configuration
111+
*
112+
* At least one of `matchmakingConfigurationName` and `matchmakingConfigurationArn` must be provided.
113+
*
114+
* @default derived from `matchmakingConfigurationArn`.
115+
*/
116+
readonly matchmakingConfigurationName?: string;
117+
118+
/**
119+
* An SNS topic ARN that is set up to receive matchmaking notifications.
120+
*
121+
* @see https://docs.aws.amazon.com/gamelift/latest/flexmatchguide/match-notification.html
122+
*
123+
* @default no notification target binded to imported ressource
124+
*/
125+
readonly notificationTarget?: sns.ITopic;
126+
}
127+
128+
/**
129+
* Properties for a new Gamelift matchmaking configuration
130+
*/
131+
export interface MatchmakingConfigurationProps {
132+
133+
/**
134+
* A unique identifier for the matchmaking configuration.
135+
* This name is used to identify the configuration associated with a matchmaking request or ticket.
136+
*/
137+
readonly matchmakingConfigurationName: string;
138+
139+
/**
140+
* A human-readable description of the matchmaking configuration.
141+
*
142+
* @default no description is provided
143+
*/
144+
readonly description?: string;
145+
146+
/**
147+
* A flag that determines whether a match that was created with this configuration must be accepted by the matched players.
148+
* With this option enabled, matchmaking tickets use the status `REQUIRES_ACCEPTANCE` to indicate when a completed potential match is waiting for player acceptance.
149+
*
150+
* @default Acceptance is not required
151+
*/
152+
readonly requireAcceptance?: boolean;
153+
154+
/**
155+
* The length of time (in seconds) to wait for players to accept a proposed match, if acceptance is required.
156+
*
157+
* @default 300 seconds
158+
*/
159+
readonly acceptanceTimeout?: cdk.Duration;
160+
161+
/**
162+
* Information to add to all events related to the matchmaking configuration.
163+
*
164+
* @default no custom data added to events
165+
*/
166+
readonly customEventData?: string;
167+
168+
/**
169+
* An SNS topic ARN that is set up to receive matchmaking notifications.
170+
*
171+
* @see https://docs.aws.amazon.com/gamelift/latest/flexmatchguide/match-notification.html
172+
*
173+
* @default no notification target
174+
*/
175+
readonly notificationTarget?: sns.ITopic;
176+
177+
/**
178+
* The maximum duration, that a matchmaking ticket can remain in process before timing out.
179+
* Requests that fail due to timing out can be resubmitted as needed.
180+
*
181+
* @default 300 seconds
182+
*/
183+
readonly requestTimeout?: cdk.Duration;
184+
185+
/**
186+
* A matchmaking rule set to use with this configuration.
187+
*
188+
* A matchmaking configuration can only use rule sets that are defined in the same Region.
189+
*/
190+
readonly ruleSet: IMatchmakingRuleSet;
191+
}
192+
193+
/**
194+
* Base class for new and imported GameLift Matchmaking configuration.
195+
*/
196+
export abstract class MatchmakingConfigurationBase extends cdk.Resource implements IMatchmakingConfiguration {
197+
198+
199+
/**
200+
* Import an existing matchmaking configuration from its attributes.
201+
*/
202+
static fromMatchmakingConfigurationAttributes(scope: Construct, id: string, attrs: MatchmakingConfigurationAttributes): IMatchmakingConfiguration {
203+
if (!attrs.matchmakingConfigurationName && !attrs.matchmakingConfigurationArn) {
204+
throw new Error('Either matchmakingConfigurationName or matchmakingConfigurationArn must be provided in MatchmakingConfigurationAttributes');
205+
}
206+
const matchmakingConfigurationName = attrs.matchmakingConfigurationName ??
207+
cdk.Stack.of(scope).splitArn(attrs.matchmakingConfigurationArn!, cdk.ArnFormat.SLASH_RESOURCE_NAME).resourceName;
208+
209+
if (!matchmakingConfigurationName) {
210+
throw new Error(`No matchmaking configuration name found in ARN: '${attrs.matchmakingConfigurationArn}'`);
211+
}
212+
213+
const matchmakingConfigurationArn = attrs.matchmakingConfigurationArn ?? cdk.Stack.of(scope).formatArn({
214+
service: 'gamelift',
215+
resource: 'matchmakingconfiguration',
216+
resourceName: attrs.matchmakingConfigurationName,
217+
arnFormat: cdk.ArnFormat.SLASH_RESOURCE_NAME,
218+
});
219+
class Import extends MatchmakingConfigurationBase {
220+
public readonly matchmakingConfigurationName = matchmakingConfigurationName!;
221+
public readonly matchmakingConfigurationArn = matchmakingConfigurationArn;
222+
public readonly notificationTarget = attrs.notificationTarget;
223+
224+
constructor(s: Construct, i: string) {
225+
super(s, i, {
226+
environmentFromArn: matchmakingConfigurationArn,
227+
});
228+
}
229+
}
230+
return new Import(scope, id);
231+
}
232+
233+
/**
234+
* The Identifier of the matchmaking configuration.
235+
*/
236+
public abstract readonly matchmakingConfigurationName: string;
237+
/**
238+
* The ARN of the matchmaking configuration.
239+
*/
240+
public abstract readonly matchmakingConfigurationArn: string;
241+
242+
/**
243+
* The notification target for matchmaking events
244+
*/
245+
public abstract readonly notificationTarget?: sns.ITopic;
246+
247+
metric(metricName: string, props?: cloudwatch.MetricOptions): cloudwatch.Metric {
248+
return new cloudwatch.Metric({
249+
namespace: 'AWS/GameLift',
250+
metricName: metricName,
251+
dimensionsMap: {
252+
MatchmakingConfigurationName: this.matchmakingConfigurationName,
253+
},
254+
...props,
255+
}).attachTo(this);
256+
}
257+
258+
metricCurrentTickets(props?: cloudwatch.MetricOptions): cloudwatch.Metric {
259+
return this.metric('CurrentTickets', props);
260+
}
261+
262+
metricMatchesAccepted(props?: cloudwatch.MetricOptions): cloudwatch.Metric {
263+
return this.metric('MatchesAccepted', props);
264+
}
265+
266+
metricMatchesCreated(props?: cloudwatch.MetricOptions): cloudwatch.Metric {
267+
return this.metric('MatchesCreated', props);
268+
}
269+
270+
metricMatchesPlaced(props?: cloudwatch.MetricOptions): cloudwatch.Metric {
271+
return this.metric('MatchesPlaced', props);
272+
}
273+
274+
metricMatchesRejected(props?: cloudwatch.MetricOptions): cloudwatch.Metric {
275+
return this.metric('MatchesRejected', props);
276+
}
277+
278+
metricPlayersStarted(props?: cloudwatch.MetricOptions): cloudwatch.Metric {
279+
return this.metric('PlayersStarted', props);
280+
}
281+
282+
metricTimeToMatch(props?: cloudwatch.MetricOptions): cloudwatch.Metric {
283+
return this.metric('TimeToMatch', props);
284+
}
285+
286+
}

packages/@aws-cdk/aws-gamelift/lib/matchmaking-ruleset.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ export abstract class MatchmakingRuleSetBase extends cdk.Resource implements IMa
105105
namespace: 'AWS/GameLift',
106106
metricName: metricName,
107107
dimensionsMap: {
108-
FleetId: this.matchmakingRuleSetName,
108+
MatchmakingRuleSetName: this.matchmakingRuleSetName,
109109
},
110110
...props,
111111
}).attachTo(this);

0 commit comments

Comments
 (0)