-
Notifications
You must be signed in to change notification settings - Fork 4
feat: Sample matchmaker and gameclient #15
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
|
||
This is a very simple game client, designed to be used with the simple-matchmaker. | ||
|
||
This app is designed to provide the simplest complete example of using the Multiplay. It uses a very simple matchmaker |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This app is designed to provide the simplest complete example of using the Multiplay. It uses a very simple matchmaker | |
This app is designed to provide the simplest complete example of using the [Unity Multiplay platform](https://unity.com/products/multiplay). It uses [simple matchmaker](../simple-matchmaker) |
or may temporarily set this for your terminal session as shown below. | ||
|
||
Windows Example: | ||
set MP_ACCESS_KEY=9ff2af788834439b83ae6692f34ea5e5 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These are randomly generated
} | ||
|
||
cfg.MatchSize = *matchSize | ||
mm := simplematchmaker.NewSimpleMatchmaker(cfg, backendClient) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
backendClient
is potentially nil
here as I only see backendClient
being set in one of the if else branches.
) | ||
|
||
var ( | ||
//go:embed assets/help_en.txt |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like the use of go embed 😃
Test evidenceThis may need a few more cycles to really nail down. Just a sample of the matchmaker and client running against the linux dev fleet which appears to be running a http server. Game Client 1:
The current output from the matchmaker, which
|
- Simple-game-client app starts | ||
- Creates a Player UUID unique for the game client run. | ||
- Repeatedly call the simple-matchmaker `/player` endpoint with the player UUID | ||
- Eventually the endpoint will return an IP and Port to connecto |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- Eventually the endpoint will return an IP and Port to connecto | |
- Eventually, the endpoint will return an IP and Port to connect to |
authService = "cf" | ||
authRegion = "eu-west-1" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are these used anywhere? I feel unused AWS4 auth vibes. :)
// setAllocationMatchInfo associates an allocation with a match. | ||
func (m *SimpleMatchmaker) setAllocationMatchInfo(allocationUUID string, matchInfo matchmaker.MatchInfo) { | ||
m.matchesMtx.Lock() | ||
m.matchesMtx.Unlock() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
missing defer?
m.matchesMtx.Unlock() | |
defer m.matchesMtx.Unlock() |
return nil | ||
} | ||
|
||
// handleConnection reflects and lines sent to it. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
typo?
// handleConnection reflects and lines sent to it. | |
// handleConnection reflects any lines sent to it. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Very cool, Lewis!
Just a few nitpicks and tidy ups before we make this public
simple-game-client/main.go
Outdated
} | ||
|
||
fmt.Printf("Connecting to match:\n") | ||
fmt.Printf(" - Allocation UUID: %s:%d\n", matchInfo.AllocationUUID) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Too many format verbs there
fmt.Printf(" - Allocation UUID: %s:%d\n", matchInfo.AllocationUUID) | |
fmt.Printf(" - Allocation UUID: %s\n", matchInfo.AllocationUUID) |
fmt.Printf(" - - %s - %s\n", pl.PlayerUUID, pl.IP) | ||
} | ||
|
||
tcpAddr, err := net.ResolveTCPAddr("tcp4", fmt.Sprintf("%s:%d", matchInfo.IP, matchInfo.Port)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nitpick, worth using net.JoinHostPort
instead for future support of IPv6?
|
||
var ( | ||
// AllocationNotFound is returned when an allocation is not found. | ||
AllocationNotFound = errors.New("allocation not found") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nitpick; sentinel errors like this should be named in the pattern ErrXXXX
AllocationNotFound = errors.New("allocation not found") | |
ErrAllocationNotFound = errors.New("allocation not found") |
const ( | ||
authService = "cf" | ||
authRegion = "eu-west-1" | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These appear to be unused
simple-matchmaker/main.go
Outdated
//"github.com/caarlos0/env" | ||
//"github.com/google/uuid" | ||
//"github.com/gorilla/mux" | ||
//"github.com/lwaddicor/hackweekmatchmaker/mpclient" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't need these any more I assume?
} | ||
content, err := ioutil.ReadAll(conn) | ||
if err != nil && !os.IsTimeout(err) { | ||
fmt.Printf("could not send to server: giving up: %s\n", err.Error()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't this be receive from server?
To use multiplay, most games need a matchmaker which groups players. | ||
For the most streamlined experience we recommend that you use the unity matchmaker to do this, but you may use an |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To use multiplay, most games need a matchmaker which groups players. | |
For the most streamlined experience we recommend that you use the unity matchmaker to do this, but you may use an | |
To use Multiplay, most games need a matchmaker which groups players. | |
For the most streamlined experience we recommend that you use the Unity Matchmaker to do this, but you may use an |
Should probably capitalise company and product names
alternative or your own custom implementation. | ||
|
||
This sample provides an incredibly simple matchmaker to get you started locally. It will group incoming players | ||
together and when enough have joined it will request a match from either its multiplay mock, or the real multiplay API. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
together and when enough have joined it will request a match from either its multiplay mock, or the real multiplay API. | |
together and when enough have joined it will request a match from either its Multiplay mock, or the real Multiplay API. |
Same as above
set MP_ACCESS_KEY=9ff2af788834439b83ae6692f34ea5e5 | ||
set MP_SECRET_KEY=6323354e200a451dba319bc1b98ade59 | ||
|
||
For example on UNIX Style OS (OSX, Linux, BSD): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For example on UNIX Style OS (OSX, Linux, BSD): | |
For example on UNIX Style OS (macOS, Linux, BSD): |
OS X became macOS a few years ago
This is a temporary package which provides multiplay API calls. This is a temporary package until the official | ||
multiplay SDK library becomes available. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a temporary package which provides multiplay API calls. This is a temporary package until the official | |
multiplay SDK library becomes available. | |
This is a temporary package which provides Multiplay API calls. This is a temporary package until the official | |
Multiplay SDK library becomes available. |
Product name
} | ||
|
||
if cfg.SecretKey == "" { | ||
return nil, fmt.Errorf("access key is empty") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
return nil, fmt.Errorf("access key is empty") | |
return nil, fmt.Errorf("secret key is empty") |
fmt.Println("Fleet: ", cfg.FleetID) | ||
fmt.Println("RegionID: ", cfg.RegionID) | ||
fmt.Println("BuildConfig(Profile): ", cfg.BuildConfig) | ||
fmt.Println("UUID: ", allocUUID) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fmt.Println("Fleet: ", cfg.FleetID) | |
fmt.Println("RegionID: ", cfg.RegionID) | |
fmt.Println("BuildConfig(Profile): ", cfg.BuildConfig) | |
fmt.Println("UUID: ", allocUUID) | |
fmt.Println("FleetID: ", cfg.FleetID) | |
fmt.Println("RegionID: ", cfg.RegionID) | |
fmt.Println("BuildConfigID(ProfileID): ", cfg.BuildConfig) | |
fmt.Println("UUID: ", allocUUID) |
These are all IDs, so I'd suggest keeping the names aligned
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fmt.Println("Fleet: ", cfg.FleetID) | |
fmt.Println("RegionID: ", cfg.RegionID) | |
fmt.Println("BuildConfig(Profile): ", cfg.BuildConfig) | |
fmt.Println("UUID: ", allocUUID) | |
fmt.Println("Fleet: ", cfg.FleetID) | |
fmt.Println("Region: ", cfg.RegionID) | |
fmt.Println("BuildConfig(Profile): ", cfg.BuildConfig) | |
fmt.Println("Allocation: ", allocUUID) |
Alternatively, drop the ID suffix
continue | ||
} | ||
|
||
// Spawn a goroutine to wait for this allocation to be processed be multiplay. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// Spawn a goroutine to wait for this allocation to be processed be multiplay. | |
// Spawn a goroutine to wait for this allocation to be processed by multiplay. |
This adds a simple matchmaker and a simple game client example.
It is designed to get a simple end to end running and not as an example of a production matchmaker. For this the unity matchmaker is recommended