Skip to content

Godot 4 AWS Plugin v 1.0.0 #66

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

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
439 changes: 0 additions & 439 deletions GodotSample/AWSGameSDK/AWSGameSDK.gd

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -3,33 +3,21 @@

extends Node

# TODO: Add the login endpoint here
const login_endpoint = "https://YOUR_ENDPOINT/prod/"
# TODO: Add your Amazon GameLift backend component endpoint here
const gamelift_integration_backend_endpoint = "https://YOUR_ENDPOINT/prod"
# TODO: set your gamelift_integration_backend_endpoint on the AWSGameSDKBackend property page

var aws_game_sdk
@onready var aws_games_sdk_auth = get_node("AWSGameSDKAuth")
@onready var aws_games_sdk_backend = get_node("AWSGameSDKBackend")

var ticket_id
var total_tries = 0 # The amount of tries to get match status

var latency_data # The JSON latency data for requesting matchmaking

func save_login_data(user_id, guest_secret):
var file = FileAccess.open("user://save_game.dat", FileAccess.WRITE)
file.store_pascal_string(user_id)
file.store_pascal_string(guest_secret)
file = null

func load_login_data():
var file = FileAccess.open("user://save_game2.dat", FileAccess.READ)
if(file == null or file.get_length() == 0):
return null;

var user_id = file.get_pascal_string()
var guest_secret = file.get_pascal_string()
return [user_id, guest_secret]


var logged_in: bool = false
var actions: Array
var current_action: String


# Measures TCP latency to an endpoint with 3 requests (1 for establishing HTTPS, 2 for average TCP)
func measure_tcp_latency(endpoint):

Expand Down Expand Up @@ -124,7 +112,7 @@ func measure_latencies():
var latencydata = { "latencyInMs": { "us-east-1": region1latency, "us-west-2": region2latency, "eu-west-1": region3latency}}

return JSON.stringify(latencydata)
#func _http_request_completed(result, response_code, headers, body):


# Called when the node enters the scene tree for the first time.
func _ready():
Expand All @@ -135,46 +123,47 @@ func _ready():
print("Got latency data: " + self.latency_data)

# Get the SDK and Init
self.aws_game_sdk = get_node("/root/AwsGameSdk")
self.aws_game_sdk.init(self.login_endpoint, self.on_login_error)
aws_games_sdk_auth.init()
aws_games_sdk_auth.aws_login_success.connect(_on_login_success)
aws_games_sdk_auth.aws_login_error.connect(_on_login_error)
aws_games_sdk_auth.aws_sdk_error.connect(_on_aws_sdk_error)
aws_games_sdk_backend.aws_backend_request_successful.connect(_on_gamelift_backend_post_response)
aws_games_sdk_backend.aws_sdk_error.connect(_on_aws_sdk_error)
print("calling login")
aws_games_sdk_auth.login()

# Try to load existing user info
var stored_user_info = self.load_login_data()

# If we have stored user info, login with existing user
if(stored_user_info != null):
print("Logging in with existing user: " + stored_user_info[0])
self.aws_game_sdk.login_as_guest(stored_user_info[0], stored_user_info[1], self.login_callback)
# Else we login as new user
else:
print("Logging in as new user")
self.aws_game_sdk.login_as_new_guest_user(self.login_callback)

# Called on any login or token refresh failures
func on_login_error(message):
func _on_login_error(message):
print("Login error: " + message)


func _on_aws_sdk_error(error_text):
print("Error received from AWS SDK: ", error_text)

# Receives a UserInfo object after successful login
func login_callback(user_info):
print("Received login info.")
print(user_info)

# Store the login info for future logins
self.save_login_data(user_info.user_id, user_info.guest_secret)

func _on_login_success():
print("Received login success")
logged_in = true
actions = ['create_ticket', 'get_ticket_data']
current_action = actions.pop_front()
#you can inspect the user_info with this line
#print(aws_games_sdk_auth.user_info.to_string())
# Start matchmaking
self.aws_game_sdk.backend_post_request(self.gamelift_integration_backend_endpoint, "/request-matchmaking",
self.latency_data, self.matchmaking_request_callback)
self.aws_games_sdk_backend.gamelift_backend_post_request(aws_games_sdk_auth.get_auth_token(),
self.latency_data)

func _on_gamelift_backend_post_response(body):
if current_action == 'create_ticket':
matchmaking_request_callback(body)
current_action = actions.pop_front()
elif current_action == 'get_ticket_data':
get_match_status_callback(body)

# We need to use the exact format of the callback required for HTTPRequest
func matchmaking_request_callback(result, response_code, headers, body):

func matchmaking_request_callback(body):
var string_response = body.get_string_from_utf8()

if(response_code >= 400):
print("Error code " + str(response_code) + " Message: " + string_response)
return

print("Matchmaking request response: " + string_response)

# Extract the ticket ID from the response
Expand All @@ -187,10 +176,11 @@ func matchmaking_request_callback(result, response_code, headers, body):
self.ticket_id = dict_response.data["TicketId"]
print("Ticket id: " + self.ticket_id)
# Call the get match status
self.aws_game_sdk.backend_get_request(self.gamelift_integration_backend_endpoint, "/get-match-status", { "ticketId" : self.ticket_id}, self.get_match_status_callback)
self.aws_game_sdk.gamelift_backend_get_request(aws_games_sdk_auth.get_auth_token(),
{ "ticketId" : self.ticket_id})

# We need to use the exact format of the callback required for HTTPRequest
func get_match_status_callback(result, response_code, headers, body):
func get_match_status_callback(body):

var string_response = body.get_string_from_utf8()

Expand All @@ -213,14 +203,15 @@ func get_match_status_callback(result, response_code, headers, body):
print("Couldn't get a valid response from matchmaking")
else:
await get_tree().create_timer(1.5).timeout
self.aws_game_sdk.backend_get_request(self.gamelift_integration_backend_endpoint, "/get-match-status", { "ticketId" : self.ticket_id}, self.get_match_status_callback)
#TODO: change this call
self.aws_game_sdk.gamelift_backend_get_request(aws_games_sdk_auth.get_auth_token(),
{ "ticketId" : self.ticket_id})
elif ticket_status == "MatchmakingSucceeded":
print("Matchmaking done, connect to server...")
# TODO: Connect
self.connect_to_server(dict_response.data["IpAddress"], dict_response.data["Port"], dict_response.data["PlayerSessionId"])
else:
print("Matchmaking failed or timed out.")

self.total_tries += 1

func connect_to_server(host, port, player_session_id):
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
uid://bj1uupijq8a0p
Original file line number Diff line number Diff line change
@@ -1,8 +1,16 @@
[gd_scene load_steps=2 format=3 uid="uid://d2rykx55ylfax"]
[gd_scene load_steps=4 format=3 uid="uid://d2rykx55ylfax"]

[ext_resource type="Script" path="res://BackendFeatures/AmazonGameLiftIntegration/AmazonGameLiftIntegration.gd" id="1_f5d5y"]
[ext_resource type="Script" uid="uid://bj1uupijq8a0p" path="res://BackendFeatures/AmazonGameLiftIntegration/AmazonGameLiftIntegration.gd" id="1_f5d5y"]
[ext_resource type="Script" uid="uid://dxp7lgvaxrjry" path="res://addons/AWSGameSDK/scripts/AWSAuthorization.gd" id="2_6och4"]
[ext_resource type="Script" uid="uid://c1iyo651ktydf" path="res://addons/AWSGameSDK/scripts/AWSBackend.gd" id="3_tqorc"]

[node name="Node2D" type="Node2D"]

[node name="Test" type="Node" parent="."]
script = ExtResource("1_f5d5y")

[node name="AWSGameSDKAuth" type="Node" parent="."]
script = ExtResource("2_6och4")
metadata/_custom_type_script = "uid://dxp7lgvaxrjry"

[node name="AWSGameSDKBackend" type="Node" parent="."]
script = ExtResource("3_tqorc")
metadata/_custom_type_script = "uid://c1iyo651ktydf"
179 changes: 149 additions & 30 deletions GodotSample/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,48 +2,170 @@

The AWS Game Backend Framework Godot 4 SDK provides integrations to the custom identity component, managed refreshing of access tokens, helper methods for calling custom backend features, and samples for integrating with different game platforms.

# SDK Overview
# SDK Overview - Now a Godot Plugin

## Initializing the SDK
The AWS Game SDK has been updated to now be installed and used as a plugin in Godot 4.x.

The AWS Game SDK has to be configured in your Godot 4 project in _Project Settings -> Autoload_ with the name _AwsGameSdk_.
To begin using the plugin, copy the ./addons/AWSGameSDK directory to your projects ./addons directory. It should appear as it does in the picture below.

The Initializing and accessing the AWS Game SDK within Godot 4 (see the Godot 4 Integration Samples for sample code):
![Godot4 Folder Structure with AWS Games SDK Plugin](images_readme/folder_structure.png)

Next, go to Project -> Project Settings... from your menu and enable the AWS Games SDK plugin by checking the checkbox.

![AWS for Games SDK Plugin enabled for a Godot project](images_readme/project_settings.png)

## Adding nodes for the AWS for Games SDK to your scenes

The AWS Game SDK contains two components that can be added to your projects. These are `AWSGameSDKAuth` and `AWSGameSDKBackend`. The AWSGameSDKAuth component allows you to login as guest, refresh your access token, and link accounts to Facebook, Apple, Google Play, and Steam via an API endpoint. The AWSGameSDKBackend component allows you to make calls to a backend endpoint to save and retrieve player data. You can add the necessary nodes to an appropriate scene for your project. The AWSGameSDKBackend requires the AWSGameSDKAuth component, as access tokens are required to save and retrieve data. These components can be added by adding child nodes to your scene.

![Adding AWSGameSDK nodes to your Godot scene](images_readme/add_aws_nodes_to_your_scene.png)

Once added, your scene tree should look similar to this.

![A Godot scene with nodes added for AWSGameSDKAuth and AWSGameSDKBackend](images_readme/scene_tree_with_plugins.png)

The plugin also uses signals. This removes the need to register callbacks and you can setup appropriate listeners to features enabled via the plugin.

## Initializing the SDK and Login

Initialization of the SDKs has been moved to property sheets to make it easier for developers to make calls.

To complete setup of the AWSGameSDKAuth component, highlight the component in your scene tree and view the properties in the Inspector window. Update the `Login Endpoint` value with your API Gateway Login Endpoint, as shown below.

![Setting your authentication endpoint property for the AWSGameSDKAuth component](images_readme/setting_auth_endpoint.png)

To complete setup of the AWSGameSDKBackend component, highlight the component in your scene tree and view the properties in the Inspector window. Update the `Backend Endpoint` value with your API Gateway Backend Endpoint, as shown below. You can leave the URIs as default.

![Setting your backend endpoint property for the AWSGameSDKAuth component](images_readme/setting_backend_endpoint.png)

In your scene's code, you will need to set a variable for each of the SDK components you enable

```python
@onready var aws_games_sdk_auth = get_node("AWSGameSDKAuth")
@onready var aws_games_sdk_backend = get_node("AWSGameSDKBackend")
```

Within the `_ready` function, connect your local functions to the signals from the SDK:

```python
func _ready():
# Get the SDK and Init
aws_games_sdk_auth.init() #initialize the Auth SDK
aws_games_sdk_auth.aws_login_success.connect(_on_login_success) #handle successful logins
aws_games_sdk_auth.aws_login_error.connect(_on_login_error) #handle login errors
aws_games_sdk_auth.aws_sdk_error.connect(_on_aws_sdk_error) #handle general SDK errors
aws_games_sdk_backend.aws_backend_request_successful.connect(_on_backend_request_success) #handle successful backend requests
aws_games_sdk_backend.aws_sdk_error.connect(_on_aws_sdk_error) #handle errors from backend requests
```

To begin the login process, call login on the AWSGameSDKAuth component, as such:

```python
aws_games_sdk_auth.login()
```

Errors for login can be managed with similar functions to those below:

```
func _on_login_error(message):
print("Login error: " + message)


# Receives a UserInfo object after successful login
func _on_login_success():
print("Received login success")
```

## Set and Get Data from your custom backend

Setting and getting data to and from your backend uses the AWSGameSDKBackend with the `backend_set_request` and `backend_get_request` functions. Both of these functions use HTTP GET requests. To set data, use the following syntax:

```python
aws_games_sdk_backend.backend_set_request(aws_games_sdk_auth.get_auth_token(), {"player_name" : "John Doe"})
```

In this case, the auth_token to make the call is retrieved from the aws_games_sdk_auth component and the `player_name` is set to `John Doe`. Multiple values can be set in a single dictionary request.

To retrieve data, use the following syntax:

```python
aws_games_sdk_backend.backend_get_request(aws_games_sdk_auth.get_auth_token())
```

This call only requires the auth_token from the aws_games_sdk_auth component.

Success and errors of both calls are handled through signal connections that were added to the `_ready` function above. A sample success function is as follows:

```python
# Get the SDK and Init
self.aws_game_sdk = get_node("/root/AwsGameSdk")
self.aws_game_sdk.init(self.login_endpoint, self.on_login_error)
func _on_backend_request_success():
print("Backend request successful")
print("Data returned from action: ", aws_games_sdk_backend.get_response_data())
```

## SDK Public API

The public API for the SDK includes the following methods. Most of them will require you to provide a callback for results (see the Godot 4 Integration Samples for sample code):
The public API for the AWSGameSDKAuth component includes the following methods. Most of them will require you to provide a callback for results (see the Godot 4 Integration Samples for sample code):

```text
func init(login_endpoint, login_error_callback)
func login_as_new_guest_user(login_callback)
func login_as_guest(user_id, guest_secret, login_callback)
func login_with_refresh_token(refresh_token, login_callback = null)
func link_steam_id_to_current_user(steam_token, login_callback_steam)
func login_with_steam_token(steam_token, login_callback)
func link_apple_id_to_current_user(apple_auth_token, login_callback_apple)
func login_with_apple_id_token(apple_auth_token, login_callback)
func link_google_play_id_to_current_user(google_play_auth_token, login_callback_google)
func login_with_google_play_token(google_play_auth_token, login_callback)
func link_facebook_id_to_current_user(facebook_access_token, facebook_user_id, login_callback_facebook)
func login_with_facebook_access_token(facebook_access_token, facebook_user_id, login_callback)
func backend_get_request(url, resource, query_parameters, callback)
func backend_post_request(url, resource, request_body, callback):
func init()
func login()
func login_with_refresh_token()
func get_auth_token() String
func link_steam_id_to_current_user(steam_token)
func login_with_steam_token(steam_token)
func link_apple_id_to_current_user(apple_auth_token)
func login_with_apple_id_token(apple_auth_token)
func link_google_play_id_to_current_user(google_play_auth_token)
func login_with_google_play_token(google_play_auth_token)
func link_facebook_id_to_current_user(facebook_access_token, facebook_user_id)
func login_with_facebook_access_token(facebook_access_token, facebook_user_id)
```

Supported signals are:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Recommended update: Add comprehensive signal documentation:

## Signal Reference

### AWSGameSDKAuth Signals
- `aws_login_success`: Emitted when login is successful. No parameters.
- `aws_login_error(message: String)`: Emitted when login fails. Provides an error message.
- `aws_sdk_error(message: String)`: Emitted when a general SDK error occurs. Provides an error message.
- `steam_link`: Emitted when Steam account linking is successful.
- `steam_login`: Emitted when Steam login is successful.
- `fb_link`: Emitted when Facebook account linking is successful.
- `fb_login`: Emitted when Facebook login is successful.
- `apple_link`: Emitted when Apple account linking is successful.
- `apple_login`: Emitted when Apple login is successful.
- `goog_link`: Emitted when Google Play account linking is successful.
- `goog_login`: Emitted when Google Play login is successful.

### AWSGameSDKBackend Signals
- `aws_backend_request_successful`: Emitted when a backend request completes successfully.
- `aws_sdk_error(message: String)`: Emitted when a backend request fails. Provides an error message.


```text
aws_login_success
aws_login_error
aws_sdk_error
steam_link
steam_login
fb_link
fb_login
apple_link
apple_login
goog_link
goog_login
````

The public API for the AWSGameSDKBackend component includes the following methods.

```python
func backend_get_request(auth_token)
func backend_set_request(auth_token, query_parameters)
func backend_post_request(auth_token, request_body)
func get_response_data() String
```

Supported signals are:

```text
aws_backend_request_successful
aws_sdk_error
```

## Adding the SDK to an existing project
# Migrating from prior version
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Recommended update: Enhance the migration guide with signal connection examples:

## Migrating from Callback-based to Signal-based Approach

When migrating from the previous version's callback-based approach to the new signal-based approach, you'll need to replace callback function registrations with signal connections:

### Old (Callback-based):
```gdscript
self.aws_game_sdk.login_as_new_guest_user(self.login_callback)

New (Signal-based):

@onready var aws_games_sdk_auth = get_node("AWSGameSDKAuth")

func _ready():
    aws_games_sdk_auth.aws_login_success.connect(_on_login_success)
    aws_games_sdk_auth.aws_login_error.connect(_on_login_error)
    aws_games_sdk_auth.login()

func _on_login_success():
    print("Login successful!")
    
func _on_login_error(message):
    print("Login failed: " + message)


This section describes the actions you will need to take if you had integrated the prior version of this sample with your Godot project. You should take these steps prior to integrating the new plugin. Before you make any changes, it is important to backup your project in case any errors are made.

## Unregister the AWSGameSDK Autoload
1. Open _Project Settings -> Autoload_ and select the "Globals" tab.
2. Under the "Autoload" tab, uncheck the _AWSGameSDK_ and click "Close."

To add the SDK to an existing project:
## Remove the AWSGameSDK folder from your project
This step assumes you have not added any folders, functionality, or code to the proir AWSGameSDK or the folder thereof. Highlight the folder in the File System viewer in your Godot project, right click, and choose "Delete."

1. Drag and drop the folder `AWSGameSDK` to your Godot 4 project
2. Open _Project Settings -> Autoload_, select the script `AWSGameSDK.gd` with the directory search and select _Open_. Make sure the name is _AwsGameSdk_ and select _Add_.
3. Integrate with the SDK from your custom code (see Godot 4 Integration Samples for example integrations)
## Remove the code used to integrate the AWSGameSDK from your code
This code should be highlighted in your project via the Godot IDE. The new plug-in code will operate very similar to the prior version, so it will be good to denote these areas with a comment, such as `#TODO: Add AWSGameSDK Plugin Code Here` while removing the code.

# Godot 4 Integration Samples

Expand Down Expand Up @@ -96,6 +218,3 @@ func link_google_play_id_to_current_user(google_play_auth_token, login_callback_
func login_with_google_play_token(google_play_auth_token, login_callback)
```




Loading