Skip to content

Commit 8d156b3

Browse files
authored
Merge pull request #88 from TaloDev/develop
Release 0.22.0
2 parents 9cdff0c + a86a747 commit 8d156b3

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+666
-151
lines changed

.github/workflows/ci.yml

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
name: CI
2+
3+
on: push
4+
5+
jobs:
6+
build-check:
7+
strategy:
8+
matrix:
9+
platform: ['Windows Desktop', 'macOS', 'Linux', 'Web']
10+
runs-on: ${{ matrix.platform == 'macOS' && 'macos-latest' || 'ubuntu-latest' }}
11+
12+
steps:
13+
- uses: actions/checkout@v4
14+
name: Checkout
15+
with:
16+
lfs: true
17+
18+
- uses: chickensoft-games/setup-godot@v1
19+
name: Set up Godot
20+
with:
21+
version: 4.3.0
22+
use-dotnet: false
23+
include-templates: true
24+
25+
- name: Build
26+
run: |
27+
output=$(godot --headless --export-release '${{ matrix.platform }}' 2>&1)
28+
if echo "$output" | grep -q "SCRIPT ERROR"; then
29+
exit 1
30+
fi

.gitignore

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
# Godot-specific ignores
55
.import/
66
export.cfg
7-
export_presets.cfg
87

98
# Imported translations (automatically generated from CSV files)
109
*.translation

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ channels](https://trytalo.com/channels): Send real-time messages between players
2525
- 🔧 [Steamworks integration](https://trytalo.com/steamworks-integration): Hook into Steamworks for authentication and ownership checks.
2626
- 🗣️ [Game feedback](https://trytalo.com/feedback): Collect and manage feedback from your players.
2727
- 🛡️ [Continuity](https://trytalo.com/continuity): Keep your data in-sync even when your players are offline.
28-
- 🔔 [Player presence](https://trytalo.com/player#presence): See if players are online and set custom statuses.
28+
- 🔔 [Player presence](https://trytalo.com/players#presence): See if players are online and set custom statuses.
2929

3030
## Samples included with the plugin
3131

addons/talo/apis/channels_api.gd

Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,32 @@ class_name ChannelsAPI extends TaloAPI
77

88
## Emitted when a message is received from a channel.
99
signal message_received(channel: TaloChannel, player_alias: TaloPlayerAlias, message: String)
10+
## Emitted when a player is joined to a channel.
11+
signal player_joined(channel: TaloChannel, player_alias: TaloPlayerAlias)
12+
## Emitted when a player is left from a channel.
13+
signal player_left(channel: TaloChannel, player_alias: TaloPlayerAlias)
14+
## Emitted when a channel's ownership transferred.
15+
signal channel_ownership_transferred(channel: TaloChannel, new_owner_player_alias: TaloPlayerAlias)
16+
## Emitted when a channel is deleted.
17+
signal channel_deleted(channel: TaloChannel)
1018

11-
func _ready():
19+
20+
func _ready() -> void:
1221
await Talo.init_completed
1322
Talo.socket.message_received.connect(_on_message_received)
1423

1524
func _on_message_received(res: String, data: Dictionary) -> void:
16-
if res == "v1.channels.message":
17-
message_received.emit(TaloChannel.new(data.channel), TaloPlayerAlias.new(data.playerAlias), data.message)
25+
match res:
26+
"v1.channels.message":
27+
message_received.emit(TaloChannel.new(data.channel), TaloPlayerAlias.new(data.playerAlias), data.message)
28+
"v1.channels.player-joined":
29+
player_joined.emit(TaloChannel.new(data.channel), TaloPlayerAlias.new(data.playerAlias))
30+
"v1.channels.player-left":
31+
player_left.emit(TaloChannel.new(data.channel), TaloPlayerAlias.new(data.playerAlias))
32+
"v1.channels.ownership-transferred":
33+
player_left.emit(TaloChannel.new(data.channel), TaloPlayerAlias.new(data.newOwner))
34+
"v1.channels.deleted":
35+
channel_deleted.emit(TaloChannel.new(data.channel))
1836

1937
## Get a channel by its ID.
2038
func find(channel_id: int) -> TaloChannel:
@@ -27,16 +45,16 @@ func find(channel_id: int) -> TaloChannel:
2745
return null
2846

2947
## Get a list of channels that players can join.
30-
func get_channels(page: int) -> Array:
48+
func get_channels(page: int) -> ChannelPage:
3149
var res = await client.make_request(HTTPClient.METHOD_GET, "?page=%s" % page)
3250

3351
match (res.status):
3452
200:
3553
var channels: Array[TaloChannel] = []
3654
channels.assign(res.body.channels.map(func (channel: Dictionary): return TaloChannel.new(channel)))
37-
return [channels, res.body.count, res.body.isLastPage]
55+
return ChannelPage.new(channels, res.body.count, res.body.isLastPage)
3856
_:
39-
return []
57+
return null
4058

4159
## Get a list of channels that the current player is subscribed to.
4260
func get_subscribed_channels() -> Array[TaloChannel]:
@@ -138,3 +156,14 @@ func send_message(channel_id: int, message: String) -> void:
138156
},
139157
message = message
140158
})
159+
160+
# Structs
161+
class ChannelPage:
162+
var channels: Array[TaloChannel]
163+
var count: int
164+
var is_last_page: bool
165+
166+
func _init(channels: Array[TaloChannel], count: int, is_last_page: bool) -> void:
167+
self.channels = channels
168+
self.count = count
169+
self.is_last_page = is_last_page

addons/talo/apis/events_api.gd

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ func track(name: String, props: Dictionary = {}) -> void:
4646
_queue.push_back({
4747
name = name,
4848
props = final_props.map(func (prop: TaloProp): return prop.to_dictionary()),
49-
timestamp = TimeUtils.get_timestamp_msec()
49+
timestamp = TaloTimeUtils.get_timestamp_msec()
5050
})
5151

5252
if _queue.size() >= _min_queue_size:

addons/talo/apis/game_config_api.gd

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,12 @@ func _on_message_received(res: String, data: Dictionary) -> void:
2020
live_config_updated.emit(TaloLiveConfig.new(data.config))
2121

2222
## Get the live config for your game.
23-
func get_live_config() -> void:
23+
func get_live_config() -> TaloLiveConfig:
2424
var res = await client.make_request(HTTPClient.METHOD_GET, "/")
2525
match (res.status):
2626
200:
2727
Talo.live_config = TaloLiveConfig.new(res.body.config)
2828
live_config_loaded.emit(Talo.live_config)
29+
return Talo.live_config
30+
_:
31+
return null

addons/talo/apis/leaderboards_api.gd

Lines changed: 34 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,13 @@ func get_cached_entries_for_current_player(internal_name: String) -> Array:
2222
)
2323

2424
## Get a list of entries for a leaderboard. The page parameter is used for pagination.
25-
func get_entries(internal_name: String, page: int, alias_id = -1, include_archived = false) -> Array:
25+
func get_entries(internal_name: String, page: int, alias_id = -1, include_archived = false) -> EntriesPage:
2626
var url = "/%s/entries?page=%s"
2727
var url_data = [internal_name, page]
2828

2929
if alias_id != -1:
3030
url += "&aliasId=%s"
31-
url_data += alias_id
31+
url_data.append(alias_id)
3232

3333
if include_archived:
3434
url += "&withDeleted=1"
@@ -37,32 +37,32 @@ func get_entries(internal_name: String, page: int, alias_id = -1, include_archiv
3737

3838
match (res.status):
3939
200:
40-
var entries: Array = res.body.entries.map(
41-
func (data: Dictionary):
40+
var entries: Array[TaloLeaderboardEntry] = Array(res.body.entries.map(
41+
func(data: Dictionary):
4242
var entry = TaloLeaderboardEntry.new(data)
4343
_entries_manager.upsert_entry(internal_name, entry)
4444

4545
return entry
46-
)
47-
return [entries, res.body.count, res.body.isLastPage]
46+
), TYPE_OBJECT, (TaloLeaderboardEntry as Script).get_instance_base_type(), TaloLeaderboardEntry)
47+
return EntriesPage.new(entries, res.body.count, res.body.isLastPage)
4848
_:
49-
return []
49+
return null
5050

5151
## Get a list of entries for a leaderboard for the current player. The page parameter is used for pagination.
52-
func get_entries_for_current_player(internal_name: String, page: int, include_archived = false) -> Array:
52+
func get_entries_for_current_player(internal_name: String, page: int, include_archived = false) -> EntriesPage:
5353
if Talo.identity_check() != OK:
54-
return []
54+
return null
5555

5656
return await get_entries(internal_name, page, Talo.current_alias.id, include_archived)
5757

5858
## Add an entry to a leaderboard. The props (key-value pairs) parameter is used to store additional data with the entry.
59-
func add_entry(internal_name: String, score: float, props: Dictionary = {}) -> Array:
59+
func add_entry(internal_name: String, score: float, props: Dictionary = {}) -> AddEntryResult:
6060
if Talo.identity_check() != OK:
61-
return []
61+
return null
6262

63-
var props_to_send = props.keys().map(func (key: String): return { key = key, value = str(props[key]) })
63+
var props_to_send: Array = props.keys().map(func(key: String) -> Dictionary: return {key = key, value = str(props[key])})
6464

65-
var res = await client.make_request(HTTPClient.METHOD_POST, "/%s/entries" % internal_name, {
65+
var res := await client.make_request(HTTPClient.METHOD_POST, "/%s/entries" % internal_name, {
6666
score = score,
6767
props = props_to_send
6868
})
@@ -72,6 +72,25 @@ func add_entry(internal_name: String, score: float, props: Dictionary = {}) -> A
7272
var entry = TaloLeaderboardEntry.new(res.body.entry)
7373
_entries_manager.upsert_entry(internal_name, entry)
7474

75-
return [entry, res.body.updated]
75+
return AddEntryResult.new(entry, res.body.updated)
7676
_:
77-
return []
77+
return null
78+
79+
# Structs
80+
class EntriesPage:
81+
var entries: Array[TaloLeaderboardEntry]
82+
var count: int
83+
var is_last_page: bool
84+
85+
func _init(entries: Array[TaloLeaderboardEntry], count: int, is_last_page: bool) -> void:
86+
self.entries = entries
87+
self.count = count
88+
self.is_last_page = is_last_page
89+
90+
class AddEntryResult:
91+
var entry: TaloLeaderboardEntry
92+
var updated: bool
93+
94+
func _init(entry: TaloLeaderboardEntry, updated: bool) -> void:
95+
self.entry = entry
96+
self.updated = updated

addons/talo/apis/player_auth_api.gd

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,14 @@ class_name PlayerAuthAPI extends TaloAPI
55
##
66
## @tutorial: https://docs.trytalo.com/docs/godot/player-authentication
77

8+
enum LoginResult {
9+
OK,
10+
FAILED,
11+
VERIFICATION_REQUIRED,
12+
}
13+
814
var session_manager = TaloSessionManager.new()
9-
var last_error: Variant = null
15+
var last_error: TaloAuthError = null
1016

1117
func _handle_error(res: Dictionary, ret: Variant = FAILED) -> Variant:
1218
if res.body != null and res.body.has("errorCode"):
@@ -37,7 +43,7 @@ func register(identifier: String, password: String, email: String = "", verifica
3743
return _handle_error(res)
3844

3945
## Log in to an existing player account. If verification is required, a verification code will be sent to the player's email.
40-
func login(identifier: String, password: String) -> Array[Variant]: ## [Error, bool]
46+
func login(identifier: String, password: String) -> LoginResult:
4147
var res = await client.make_request(HTTPClient.METHOD_POST, "/login", {
4248
identifier = identifier,
4349
password = password
@@ -50,9 +56,12 @@ func login(identifier: String, password: String) -> Array[Variant]: ## [Error, b
5056
else:
5157
session_manager.handle_session_created(res.body.alias, res.body.sessionToken, res.body.socketToken)
5258

53-
return [OK, res.body.has("verificationRequired")]
59+
if res.body.has("verificationRequired"):
60+
return LoginResult.VERIFICATION_REQUIRED
61+
else:
62+
return LoginResult.OK
5463
_:
55-
return _handle_error(res, [FAILED, false])
64+
return _handle_error(res, LoginResult.FAILED)
5665

5766
## Verify a player account using the verification code sent to the player's email.
5867
func verify(verification_code: String) -> Error:
@@ -110,7 +119,7 @@ func forgot_password(email: String) -> Error:
110119
204:
111120
return OK
112121
_:
113-
return FAILED
122+
return _handle_error(res)
114123

115124
## Reset the password of the player account using the code sent to the player's email.
116125
func reset_password(code: String, password: String) -> Error:

addons/talo/apis/players_api.gd

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,30 +9,38 @@ class_name PlayersAPI extends TaloAPI
99
signal identified(player: TaloPlayer)
1010

1111
## Identify a player using a service (e.g. "username") and identifier (e.g. "bob").
12-
func identify(service: String, identifier: String) -> void:
12+
func identify(service: String, identifier: String) -> TaloPlayer:
1313
var res = await client.make_request(HTTPClient.METHOD_GET, "/identify?service=%s&identifier=%s" % [service, identifier])
1414
match (res.status):
1515
200:
1616
Talo.current_alias = TaloPlayerAlias.new(res.body.alias)
1717
Talo.socket.set_socket_token(res.body.socketToken)
1818
identified.emit(Talo.current_player)
19+
return Talo.current_player
1920
_:
2021
if not await Talo.is_offline():
2122
Talo.player_auth.session_manager.clear_session()
23+
return null
2224

2325
## Identify a player using a Steam ticket.
24-
func identify_steam(ticket: String, identity: String = "") -> void:
26+
func identify_steam(ticket: String, identity: String = "") -> TaloPlayer:
2527
if identity.is_empty():
26-
identify("steam", ticket)
28+
return await identify("steam", ticket)
2729
else:
28-
identify("steam", "%s:%s" % [identity, ticket])
30+
return await identify("steam", "%s:%s" % [identity, ticket])
2931

3032
## Flush and sync the player's current data with Talo.
31-
func update() -> void:
33+
func update() -> TaloPlayer:
3234
var res = await client.make_request(HTTPClient.METHOD_PATCH, "/%s" % Talo.current_player.id, { props = Talo.current_player.get_serialized_props() })
3335
match (res.status):
3436
200:
35-
Talo.current_alias.player = TaloPlayer.new(res.body.player)
37+
if is_instance_valid(Talo.current_alias.player):
38+
Talo.current_alias.player.update_from_raw_data(res.body.player)
39+
else:
40+
Talo.current_alias.player = TaloPlayer.new(res.body.player)
41+
return Talo.current_player
42+
_:
43+
return null
3644

3745
## Merge all of the data from player_id2 into player_id1 and delete player_id2.
3846
func merge(player_id1: String, player_id2: String) -> TaloPlayer:
@@ -58,7 +66,7 @@ func find(player_id: String) -> TaloPlayer:
5866

5967
## Generate a mostly-unique identifier.
6068
func generate_identifier() -> String:
61-
var time_hash: String = str(TimeUtils.get_timestamp_msec()).sha256_text()
69+
var time_hash: String = str(TaloTimeUtils.get_timestamp_msec()).sha256_text()
6270
var size = 12
6371
var split_start: int = RandomNumberGenerator.new().randi_range(0, time_hash.length() - size)
6472
return time_hash.substr(split_start, size)

addons/talo/apis/saves_api.gd

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ var current: TaloGameSave:
2929
## Sync an offline save with an online save using the offline save data.
3030
func replace_save_with_offline_save(offline_save: TaloGameSave) -> TaloGameSave:
3131
var res = await client.make_request(HTTPClient.METHOD_PATCH, "/%s" % offline_save.id, {
32-
name=offline_save.display_name,
32+
name=offline_save.name,
3333
content=offline_save.content
3434
})
3535

@@ -68,6 +68,8 @@ func get_saves() -> Array[TaloGameSave]:
6868
## Set the chosen save and optionally (default true) load it.
6969
func choose_save(save: TaloGameSave, load_save = true) -> void:
7070
_saves_manager.set_chosen_save(save, load_save)
71+
if load_save:
72+
save_chosen.emit(save)
7173

7274
## Unload the current save.
7375
func unload_current_save() -> void:
@@ -84,7 +86,7 @@ func create_save(save_name: String, content: Dictionary = {}) -> TaloGameSave:
8486
save = TaloGameSave.new({
8587
name=save_name,
8688
content=save_content,
87-
updatedAt=TimeUtils.get_current_datetime_string()
89+
updatedAt=TaloTimeUtils.get_current_datetime_string()
8890
})
8991
else:
9092
var res = await client.make_request(HTTPClient.METHOD_POST, "/", {
@@ -108,7 +110,9 @@ func register(loadable: TaloLoadable) -> void:
108110

109111
## Mark an object as loaded.
110112
func set_object_loaded(id: String) -> void:
111-
_saves_manager.set_object_loaded(id)
113+
_saves_manager.push_loaded_object(id)
114+
if _saves_manager.is_loading_completed():
115+
save_loading_completed.emit()
112116

113117
## Update the currently loaded save using the current state of the game and with the given name.
114118
func update_current_save(new_name: String = "") -> TaloGameSave:
@@ -120,16 +124,16 @@ func update_save(save: TaloGameSave, new_name: String = "") -> TaloGameSave:
120124

121125
if await Talo.is_offline():
122126
if not new_name.is_empty():
123-
save.display_name = new_name
127+
save.name = new_name
124128

125129
save.content = content
126-
save.updated_at = TimeUtils.get_current_datetime_string()
130+
save.updated_at = TaloTimeUtils.get_current_datetime_string()
127131
else:
128132
if Talo.identity_check() != OK:
129133
return
130134

131135
var res = await client.make_request(HTTPClient.METHOD_PATCH, "/%s" % save.id, {
132-
name=save.display_name if new_name.is_empty() else new_name,
136+
name=save.name if new_name.is_empty() else new_name,
133137
content=content
134138
})
135139

0 commit comments

Comments
 (0)