Signup form

This commit is contained in:
Layla 2020-08-15 17:42:49 -04:00
parent a5363ac8dd
commit 089013e985
No known key found for this signature in database
GPG Key ID: A494D9357BA1BE31
22 changed files with 7547 additions and 7 deletions

View File

@ -0,0 +1,58 @@
tool
extends Node
# The default host address of the server.
const DEFAULT_HOST : String = "127.0.0.1"
# The default port number of the server.
const DEFAULT_PORT : int = 7350
# The default timeout for the connections.
const DEFAULT_TIMEOUT = 3
# The default protocol scheme for the client connection.
const DEFAULT_CLIENT_SCHEME : String = "http"
# The default protocol scheme for the socket connection.
const DEFAULT_SOCKET_SCHEME : String = "ws"
# The default log level for the Nakama logger.
const DEFAULT_LOG_LEVEL = NakamaLogger.LOG_LEVEL.DEBUG
var _http_adapter = null
var logger = NakamaLogger.new()
func get_client_adapter() -> NakamaHTTPAdapter:
if _http_adapter == null:
_http_adapter = NakamaHTTPAdapter.new()
_http_adapter.logger = logger
_http_adapter.name = "NakamaHTTPAdapter"
add_child(_http_adapter)
return _http_adapter
func create_socket_adapter() -> NakamaSocketAdapter:
var adapter = NakamaSocketAdapter.new()
adapter.name = "NakamaWebSocketAdapter"
adapter.logger = logger
add_child(adapter)
return adapter
func create_client(p_server_key : String,
p_host : String = DEFAULT_HOST,
p_port : int = DEFAULT_PORT,
p_scheme : String = DEFAULT_CLIENT_SCHEME,
p_timeout : int = DEFAULT_TIMEOUT,
p_log_level : int = DEFAULT_LOG_LEVEL) -> NakamaClient:
logger._level = p_log_level
return NakamaClient.new(get_client_adapter(), p_server_key, p_scheme, p_host, p_port, p_timeout)
func create_socket(p_host : String = DEFAULT_HOST,
p_port : int = DEFAULT_PORT,
p_scheme : String = DEFAULT_SOCKET_SCHEME) -> NakamaSocket:
return NakamaSocket.new(create_socket_adapter(), p_host, p_port, p_scheme, true)
func create_socket_from(p_client : NakamaClient) -> NakamaSocket:
var scheme = "ws"
if p_client.scheme == "https":
scheme = "wss"
return NakamaSocket.new(create_socket_adapter(), p_client.host, p_client.port, scheme, true)

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,576 @@
extends NakamaAsyncResult
class_name NakamaRTAPI
# A chat channel on the server.
class Channel extends NakamaAsyncResult:
const _SCHEMA = {
"id": {"name": "id", "type": TYPE_STRING, "required": true},
"presences": {"name": "presences", "type": TYPE_ARRAY, "required": true, "content": "UserPresence"},
"self": {"name": "self_presence", "type": "UserPresence", "required": true},
"room_name": {"name": "room_name", "type": TYPE_STRING, "required": false},
"group_id": {"name": "group_id", "type": TYPE_STRING, "required": false},
"user_id_one": {"name": "user_id_one", "type": TYPE_STRING, "required": false},
"user_id_two": {"name": "user_id_two", "type": TYPE_STRING, "required": false}
}
# The server-assigned channel ID.
var id : String
# The presences visible on the chat channel.
var presences : Array # of objects NakamaUserPresence
# The presence of the current user. i.e. Your self.
var self_presence : NakamaRTAPI.UserPresence
# The name of the chat room, or an empty string if this message was not sent through a chat room.
var room_name : String
# The ID of the group, or an empty string if this message was not sent through a group channel.
var group_id : String
# The ID of the first DM user, or an empty string if this message was not sent through a DM chat.
var user_id_one : String
# The ID of the second DM user, or an empty string if this message was not sent through a DM chat.
var user_id_two : String
func _init(p_ex = null).(p_ex):
pass
func _to_string():
if is_exception(): return get_exception()._to_string()
return "Channel<id=%s, presences=%s, self=%s, room_name=%s, group_id=%s, user_id_one=%s, user_id_two=%s>" % [
id, presences, self_presence, room_name, group_id, user_id_one, user_id_two
]
static func create(p_ns : GDScript, p_dict : Dictionary) -> Channel:
return _safe_ret(NakamaSerializer.deserialize(p_ns, "Channel", p_dict), Channel) as Channel
static func get_result_key() -> String:
return "channel"
class ChannelMessageAck extends NakamaAsyncResult:
const _SCHEMA = {
"channel_id": {"name": "channel_id", "type": TYPE_STRING, "required": true},
"code": {"name": "code", "type": TYPE_INT, "required": true},
"create_time": {"name": "create_time", "type": TYPE_STRING, "required": false},
"message_id": {"name": "message_id", "type": TYPE_STRING, "required": true},
"persistent": {"name": "persistent", "type": TYPE_BOOL, "required": false},
"update_time": {"name": "update_time", "type": TYPE_STRING, "required": false},
"username": {"name": "username", "type": TYPE_STRING, "required": false},
"room_name": {"name": "room_name", "type": TYPE_STRING, "required": false},
"group_id": {"name": "group_id", "type": TYPE_STRING, "required": false},
"user_id_one": {"name": "user_id_one", "type": TYPE_STRING, "required": false},
"user_id_two": {"name": "user_id_two", "type": TYPE_STRING, "required": false}
}
# The server-assigned channel ID.
var channel_id : String
# A user-defined code for the chat message.
var code : int
# The UNIX time when the message was created.
var create_time : String
# A unique ID for the chat message.
var message_id : String
# True if the chat message has been stored in history.
var persistent : bool
# The UNIX time when the message was updated.
var update_time : String
# The username of the sender of the message.
var username : String
# The name of the chat room, or an empty string if this message was not sent through a chat room.
var room_name : String
# The ID of the group, or an empty string if this message was not sent through a group channel.
var group_id : String
# The ID of the first DM user, or an empty string if this message was not sent through a DM chat.
var user_id_one : String
# The ID of the second DM user, or an empty string if this message was not sent through a DM chat.
var user_id_two : String
func _init(p_ex = null).(p_ex):
pass
func _to_string():
if is_exception(): return get_exception()._to_string()
return "ChannelMessageAck<channel_id=%s, code=%d, create_time=%s, message_id=%s, persistent=%s, update_time=%s, username=%s room_name=%s, group_id=%s, user_id_one=%s, user_id_two=%s>" % [
channel_id, code, create_time, message_id, persistent, update_time, username, room_name, group_id, user_id_one, user_id_two
]
static func create(p_ns : GDScript, p_dict : Dictionary) -> ChannelMessageAck:
return _safe_ret(NakamaSerializer.deserialize(p_ns, "ChannelMessageAck", p_dict), ChannelMessageAck) as ChannelMessageAck
static func get_result_key() -> String:
return "channel_message_ack"
# A batch of join and leave presences on a chat channel.
class ChannelPresenceEvent extends NakamaAsyncResult:
const _SCHEMA = {
"channel_id": {"name": "channel_id", "type": TYPE_STRING, "required": true},
"joins": {"name": "joins", "type": TYPE_ARRAY, "required": false, "content" : "UserPresence"},
"leaves": {"name": "leaves", "type": TYPE_ARRAY, "required": false, "content" : "UserPresence"},
"room_name": {"name": "room_name", "type": TYPE_STRING, "required": false},
"group_id": {"name": "group_id", "type": TYPE_STRING, "required": false},
"user_id_one": {"name": "user_id_one", "type": TYPE_STRING, "required": false},
"user_id_two": {"name": "user_id_two", "type": TYPE_STRING, "required": false}
}
# The unique identifier of the chat channel.
var channel_id : String
# Presences of the users who joined the channel.
var joins : Array # UserPresence
# Presences of users who left the channel.
var leaves : Array # UserPresence
# The name of the chat room, or an empty string if this message was not sent through a chat room.
var room_name : String
# The ID of the group, or an empty string if this message was not sent through a group channel.
var group_id : String
# The ID of the first DM user, or an empty string if this message was not sent through a DM chat.
var user_id_one : String
# The ID of the second DM user, or an empty string if this message was not sent through a DM chat.
var user_id_two : String
func _init(p_ex = null).(p_ex):
pass
func _to_string():
if is_exception(): return get_exception()._to_string()
return "ChannelPresenceEvent<channel_id=%s, joins=%s, leaves=%s, room_name=%s, group_id=%s, user_id_one=%s, user_id_two=%s>" % [
channel_id, joins, leaves, room_name, group_id, user_id_one, user_id_two
]
static func create(p_ns : GDScript, p_dict : Dictionary) -> ChannelPresenceEvent:
return _safe_ret(NakamaSerializer.deserialize(p_ns, "ChannelPresenceEvent", p_dict), ChannelPresenceEvent) as ChannelPresenceEvent
static func get_result_key() -> String:
return "channel_presence_event"
# A multiplayer match.
class Match extends NakamaAsyncResult:
const _SCHEMA = {
"authoritative": {"name": "authoritative", "type": TYPE_BOOL, "required": false},
"match_id": {"name": "match_id", "type": TYPE_STRING, "required": true},
"label": {"name": "label", "type": TYPE_STRING, "required": false},
"presences": {"name": "presences", "type": TYPE_ARRAY, "required": false, "content": "UserPresence"},
"size": {"name": "size", "type": TYPE_INT, "required": false},
"self": {"name": "self_user", "type": "UserPresence", "required": true}
}
# If this match has an authoritative handler on the server.
var authoritative : bool
# The unique match identifier.
var match_id : String
# A label for the match which can be filtered on.
var label : String
# The presences already in the match.
var presences : Array # UserPresence
# The number of users currently in the match.
var size : int
# The current user in this match. i.e. Yourself.
var self_user : UserPresence
func _init(p_ex = null).(p_ex):
pass
static func create(p_ns : GDScript, p_dict : Dictionary):
return _safe_ret(NakamaSerializer.deserialize(p_ns, "Match", p_dict), Match) as Match
func _to_string():
if is_exception(): return get_exception()._to_string()
return "Match<authoritative=%s, match_id=%s, label=%s, presences=%s, size=%d, self=%s>" % [authoritative, match_id, label, presences, size, self_user]
static func get_result_key() -> String:
return "match"
# Some game state update in a match.
class MatchData extends NakamaAsyncResult:
const _SCHEMA = {
"match_id": {"name": "match_id", "type": TYPE_STRING, "required": true},
"presence": {"name": "presence", "type": "UserPresence", "required": false},
"op_code": {"name": "op_code", "type": TYPE_STRING, "required": false},
"data": {"name": "data", "type": TYPE_STRING, "required": false}
}
# The unique match identifier.
var match_id : String
# The operation code for the state change.
# This value can be used to mark the type of the contents of the state.
var op_code : int = 0
# The user that sent this game state update.
var presence : UserPresence
# The byte contents of the state change.
var data : String
func _init(p_ex = null).(p_ex):
pass
func _to_string():
if is_exception(): return get_exception()._to_string()
return "MatchData<match_id=%s, op_code=%s, presence=%s, data=%s>" % [match_id, op_code, presence, data]
static func create(p_ns : GDScript, p_dict : Dictionary) -> MatchData:
var out := _safe_ret(NakamaSerializer.deserialize(p_ns, "MatchData", p_dict), MatchData) as MatchData
if out.data: # Decode base64 received data
out.data = Marshalls.base64_to_utf8(out.data)
return out
static func get_result_key() -> String:
return "match_data"
# A batch of join and leave presences for a match.
class MatchPresenceEvent extends NakamaAsyncResult:
const _SCHEMA = {
"match_id": {"name": "match_id", "type": TYPE_STRING, "required": true},
"joins": {"name": "joins", "type": TYPE_ARRAY, "required": false, "content" : "UserPresence"},
"leaves": {"name": "leaves", "type": TYPE_ARRAY, "required": false, "content" : "UserPresence"},
}
# Presences of users who joined the match.
var joins : Array
# Presences of users who left the match.
var leaves : Array
# The unique match identifier.
var match_id : String
func _init(p_ex = null).(p_ex):
pass
func _to_string():
if is_exception(): return get_exception()._to_string()
return "MatchPresenceEvent<match_id=%s, joins=%s, leaves=%s>" % [match_id, joins, leaves]
static func create(p_ns : GDScript, p_dict : Dictionary) -> MatchPresenceEvent:
return _safe_ret(NakamaSerializer.deserialize(p_ns, "MatchPresenceEvent", p_dict), MatchPresenceEvent) as MatchPresenceEvent
static func get_result_key() -> String:
return "match_presence_event"
# The result of a successful matchmaker operation sent to the server.
class MatchmakerMatched extends NakamaAsyncResult:
const _SCHEMA = {
"match_id": {"name": "match_id", "type": TYPE_STRING, "required": false},
"ticket": {"name": "ticket", "type": TYPE_STRING, "required": true},
"token": {"name": "token", "type": TYPE_STRING, "required": false},
"users": {"name": "users", "type": TYPE_ARRAY, "required": false, "content": "MatchmakerUser"},
"self": {"name": "self_user", "type": "MatchmakerUser", "required": true}
}
# The id used to join the match.
# A match ID used to join the match.
var match_id : String
# The ticket sent by the server when the user requested to matchmake for other players.
var ticket : String
# The token used to join a match.
var token : String
# The other users matched with this user and the parameters they sent.
var users : Array # MatchmakerUser
# The current user who matched with opponents.
var self_user : MatchmakerUser
func _init(p_ex = null).(p_ex):
pass
func _to_string():
if is_exception(): return get_exception()._to_string()
return "<MatchmakerMatched match_id=%s, ticket=%s, token=%s, users=%s, self=%s>" % [
match_id, ticket, token, users, self_user
]
static func create(p_ns : GDScript, p_dict : Dictionary) -> MatchmakerMatched:
return _safe_ret(NakamaSerializer.deserialize(p_ns, "MatchmakerMatched", p_dict), MatchmakerMatched) as MatchmakerMatched
static func get_result_key() -> String:
return "matchmaker_matched"
# The matchmaker ticket received from the server.
class MatchmakerTicket extends NakamaAsyncResult:
const _SCHEMA = {
"ticket": {"name": "ticket", "type": TYPE_STRING, "required": true}
}
# The ticket generated by the matchmaker.
var ticket : String
func _init(p_ex = null).(p_ex):
pass
static func create(p_ns : GDScript, p_dict : Dictionary) -> MatchmakerTicket:
return _safe_ret(NakamaSerializer.deserialize(p_ns, "MatchmakerTicket", p_dict), MatchmakerTicket) as MatchmakerTicket
func _to_string():
if is_exception(): return get_exception()._to_string()
return "<MatchmakerTicket ticket=%s>" % ticket
static func get_result_key() -> String:
return "matchmaker_ticket"
# The user with the parameters they sent to the server when asking for opponents.
class MatchmakerUser extends NakamaAsyncResult:
const _SCHEMA = {
"numeric_properties": {"name": "numeric_properties", "type": TYPE_DICTIONARY, "required": false, "content": TYPE_REAL},
"string_properties": {"name": "string_properties", "type": TYPE_DICTIONARY, "required": false, "content": TYPE_STRING},
"presence": {"name": "presence", "type": "UserPresence", "required": true}
}
# The numeric properties which this user asked to matchmake with.
var numeric_properties : Dictionary
# The presence of the user.
var presence : UserPresence
# The string properties which this user asked to matchmake with.
var string_properties : Dictionary
func _init(p_ex = null).(p_ex):
pass
func _to_string():
if is_exception(): return get_exception()._to_string()
return "<MatchmakerUser presence=%s, numeric_properties=%s, string_properties=%s>" % [
presence, numeric_properties, string_properties]
static func create(p_ns : GDScript, p_dict : Dictionary) -> MatchmakerUser:
return _safe_ret(NakamaSerializer.deserialize(p_ns, "MatchmakerUser", p_dict), MatchmakerUser) as MatchmakerUser
static func get_result_key() -> String:
return "matchmaker_user"
# Receive status updates for users.
class Status extends NakamaAsyncResult:
const _SCHEMA = {
"presences": {"name": "presences", "type": TYPE_ARRAY, "required": true, "content": "UserPresence"},
}
# The status events for the users followed.
var presences := Array()
func _init(p_ex = null).(p_ex):
pass
static func create(p_ns : GDScript, p_dict : Dictionary) -> Status:
return _safe_ret(NakamaSerializer.deserialize(p_ns, "Status", p_dict), Status) as Status
func _to_string():
if is_exception(): return get_exception()._to_string()
return "<Status presences=%s>" % [presences]
static func get_result_key() -> String:
return "status"
# A status update event about other users who've come online or gone offline.
class StatusPresenceEvent extends NakamaAsyncResult:
const _SCHEMA = {
"joins": {"name": "joins", "type": TYPE_ARRAY, "required": false, "content" : "UserPresence"},
"leaves": {"name": "leaves", "type": TYPE_ARRAY, "required": false, "content" : "UserPresence"},
}
# Presences of users who joined the server.
# This join information is in response to a subscription made to be notified when a user comes online.
var joins : Array
# Presences of users who left the server.
# This leave information is in response to a subscription made to be notified when a user goes offline.
var leaves : Array
func _init(p_ex = null).(p_ex):
pass
func _to_string():
if is_exception(): return get_exception()._to_string()
return "StatusPresenceEvent<joins=%s, leaves=%s>" % [joins, leaves]
static func create(p_ns : GDScript, p_dict : Dictionary) -> StatusPresenceEvent:
return _safe_ret(NakamaSerializer.deserialize(p_ns, "StatusPresenceEvent", p_dict), StatusPresenceEvent) as StatusPresenceEvent
static func get_result_key() -> String:
return "status_presence_event"
# A realtime socket stream on the server.
class Stream extends NakamaAsyncResult:
const _SCHEMA = {
"mode": {"name": "mode", "type": TYPE_INT, "required": true},
"subject": {"name": "subject", "type": TYPE_STRING, "required": false},
"subcontext": {"name": "subcontext", "type": TYPE_STRING, "required": false},
"label": {"name": "label", "type": TYPE_STRING, "required": false},
}
# The mode of the stream.
var mode : int
# The subject of the stream. This is usually a user id.
var subject : String
# The descriptor of the stream. Used with direct chat messages and contains a second user id.
var subcontext : String
# Identifies streams which have a context across users like a chat channel room.
var label : String
func _init(p_ex = null).(p_ex):
pass
func _to_string():
if is_exception(): return get_exception()._to_string()
return "Stream<mode=%s, subject=%s, subcontext=%s, label=%s>" % [mode, subject, subcontext, label]
static func create(p_ns : GDScript, p_dict : Dictionary) -> Stream:
return _safe_ret(NakamaSerializer.deserialize(p_ns, "Stream", p_dict), Stream) as Stream
static func get_result_key() -> String:
return "stream"
# A batch of joins and leaves on the low level stream.
# Streams are built on to provide abstractions for matches, chat channels, etc. In most cases you'll never need to
# interact with the low level stream itself.
class StreamPresenceEvent extends NakamaAsyncResult:
const _SCHEMA = {
"stream": {"name": "stream", "type": "Stream", "required": true},
"joins": {"name": "joins", "type": TYPE_ARRAY, "required": false, "content" : "UserPresence"},
"leaves": {"name": "leaves", "type": TYPE_ARRAY, "required": false, "content" : "UserPresence"},
}
# Presences of users who left the stream.
var joins : Array
# Presences of users who joined the stream.
var leaves : Array
# The identifier for the stream.
var stream : Stream = null
func _to_string():
if is_exception(): return get_exception()._to_string()
return "StreamPresenceEvent<stream=%s, joins=%s, leaves=%s>" % [stream, joins, leaves]
static func create(p_ns : GDScript, p_dict : Dictionary) -> StreamPresenceEvent:
return _safe_ret(NakamaSerializer.deserialize(p_ns, "StreamPresenceEvent", p_dict), StreamPresenceEvent) as StreamPresenceEvent
static func get_result_key() -> String:
return "stream_presence_event"
# A state change received from a stream.
class StreamData extends NakamaAsyncResult:
const _SCHEMA = {
"stream": {"name": "stream", "type": "Stream", "required": true},
"sender": {"name": "sender", "type": "UserPresence", "required": false},
"data": {"name": "state", "type": TYPE_STRING, "required": false},
"reliable": {"name": "reliable", "type": TYPE_BOOL, "required": false},
}
# The user who sent the state change. May be `null`.
var sender : UserPresence = null
# The contents of the state change.
var state : String
# The identifier for the stream.
var stream : Stream
# True if this data was delivered reliably, false otherwise.
var reliable : bool
func _to_string():
if is_exception(): return get_exception()._to_string()
return "StreamData<sender=%s, state=%s, stream=%s>" % [sender, state, stream]
static func create(p_ns : GDScript, p_dict : Dictionary) -> StreamData:
return _safe_ret(NakamaSerializer.deserialize(p_ns, "StreamData", p_dict), StreamData) as StreamData
static func get_result_key() -> String:
return "stream_data"
# An object which represents a connected user in the server.
# The server allows the same user to be connected with multiple sessions. To uniquely identify them a tuple of
# `{ node_id, user_id, session_id }` is used which is exposed as this object.
class UserPresence extends NakamaAsyncResult:
const _SCHEMA = {
"persistence": {"name": "persistence", "type": TYPE_BOOL, "required": false},
"session_id": {"name": "session_id", "type": TYPE_STRING, "required": true},
"status": {"name": "status", "type": TYPE_STRING, "required": false},
"username": {"name": "username", "type": TYPE_STRING, "required": false},
"user_id": {"name": "user_id", "type": TYPE_STRING, "required": true},
}
# If this presence generates stored events like persistent chat messages or notifications.
var persistence : bool
# The session id of the user.
var session_id : String
# The status of the user with the presence on the server.
var status : String
# The username for the user.
var username : String
# The id of the user.
var user_id : String
func _init(p_ex = null).(p_ex):
pass
func serialize() -> Dictionary:
return NakamaSerializer.serialize(self)
func _to_string():
if is_exception(): return get_exception()._to_string()
return "UserPresence<persistence=%s, session_id=%s, status=%s, username=%s, user_id=%s>" % [
persistence, session_id, status, username, user_id]
static func create(p_ns : GDScript, p_dict : Dictionary) -> UserPresence:
return _safe_ret(NakamaSerializer.deserialize(p_ns, "UserPresence", p_dict), UserPresence) as UserPresence
static func get_result_key() -> String:
return "user_presence"

View File

@ -0,0 +1,363 @@
extends Reference
class_name NakamaRTMessage
# Send a channel join message to the server.
class ChannelJoin:
const _SCHEMA = {
"persistence": {"name": "persistence", "type": TYPE_BOOL, "required": true},
"hidden": {"name": "hidden", "type": TYPE_BOOL, "required": true},
"target": {"name": "target", "type": TYPE_STRING, "required": true},
"type": {"name": "type", "type": TYPE_INT, "required": true},
}
enum ChannelType {
# A chat room which can be created dynamically with a name.
Room = 1,
# A private chat between two users.
DirectMessage = 2,
# A chat within a group on the server.
Group = 3
}
var persistence : bool
var hidden : bool
var target : String
var type : int
func _init(p_target : String, p_type : int, p_persistence : bool, p_hidden : bool):
persistence = p_persistence
hidden = p_hidden
target = p_target
type = p_type if p_type >= ChannelType.Room and p_type <= ChannelType.Group else 0 # Will cause error server side
func serialize() -> Dictionary:
return NakamaSerializer.serialize(self)
func get_msg_key() -> String:
return "channel_join"
func _to_string():
return "ChannelJoin<persistence=%s, hidden=%s, target=%s, type=%d>" % [persistence, hidden, target, type]
# A leave message for a match on the server.
class ChannelLeave extends NakamaAsyncResult:
const _SCHEMA = {
"channel_id": {"name": "channel_id", "type": TYPE_STRING, "required": true}
}
var channel_id : String
func _init(p_channel_id : String):
channel_id = p_channel_id
func serialize() -> Dictionary:
return NakamaSerializer.serialize(self)
func get_msg_key() -> String:
return "channel_leave"
func _to_string():
return "ChannelLeave<channel_id=%s>" % [channel_id]
class ChannelMessageRemove extends NakamaAsyncResult:
const _SCHEMA = {
"channel_id": {"name": "channel_id", "type": TYPE_STRING, "required": true},
"message_id": {"name": "message_id", "type": TYPE_STRING, "required": true}
}
var channel_id : String
var message_id : String
func _init(p_channel_id : String, p_message_id):
channel_id = p_channel_id
message_id = p_message_id
func serialize() -> Dictionary:
return NakamaSerializer.serialize(self)
func get_msg_key() -> String:
return "channel_message_remove"
func _to_string():
return "ChannelMessageRemove<channel_id=%s, message_id=%s>" % [channel_id, message_id]
# Send a chat message to a channel on the server.
class ChannelMessageSend extends NakamaAsyncResult:
const _SCHEMA = {
"channel_id": {"name": "channel_id", "type": TYPE_STRING, "required": true},
"content": {"name": "content", "type": TYPE_STRING, "required": true}
}
var channel_id : String
var content : String
func _init(p_channel_id : String, p_content):
channel_id = p_channel_id
content = p_content
func serialize() -> Dictionary:
return NakamaSerializer.serialize(self)
func get_msg_key() -> String:
return "channel_message_send"
func _to_string():
return "ChannelMessageSend<channel_id=%s, content=%s>" % [channel_id, content]
class ChannelMessageUpdate extends NakamaAsyncResult:
const _SCHEMA = {
"channel_id": {"name": "channel_id", "type": TYPE_STRING, "required": true},
"message_id": {"name": "message_id", "type": TYPE_STRING, "required": true},
"content": {"name": "content", "type": TYPE_STRING, "required": true}
}
var channel_id : String
var message_id : String
var content : String
func _init(p_channel_id : String, p_message_id, p_content : String):
channel_id = p_channel_id
message_id = p_message_id
content = p_content
func serialize() -> Dictionary:
return NakamaSerializer.serialize(self)
func get_msg_key() -> String:
return "channel_message_update"
func _to_string():
return "ChannelMessageUpdate<channel_id=%s, message_id=%s, content=%s>" % [channel_id, message_id, content]
# A create message for a match on the server.
class MatchCreate extends NakamaAsyncResult:
const _SCHEMA = {}
func _init():
pass
func serialize():
return NakamaSerializer.serialize(self)
func get_msg_key() -> String:
return "match_create"
func _to_string():
return "MatchCreate<>"
# A join message for a match on the server.
class MatchJoin extends NakamaAsyncResult:
const _SCHEMA = {
"match_id": {"name": "match_id", "type": TYPE_STRING, "required": false},
"token": {"name": "token", "type": TYPE_STRING, "required": false},
"metadata": {"name": "metadata", "type": TYPE_DICTIONARY, "required": false, "content": TYPE_STRING},
}
# These two are mutually exclusive and set manually by socket for now, so use null.
var match_id = null
var token = null
var metadata = null
func _init(p_ex=null).(p_ex):
pass
func serialize() -> Dictionary:
return NakamaSerializer.serialize(self)
func get_msg_key() -> String:
return "match_join"
func _to_string():
return "MatchJoin<match_id=%s, token=%s, metadata=%s>" % [match_id, token, metadata]
# A leave message for a match on the server.
class MatchLeave extends NakamaAsyncResult:
const _SCHEMA = {
"match_id": {"name": "match_id", "type": TYPE_STRING, "required": true}
}
var match_id : String
func _init(p_match_id : String):
match_id = p_match_id
func serialize() -> Dictionary:
return NakamaSerializer.serialize(self)
func get_msg_key() -> String:
return "match_leave"
func _to_string():
return "MatchLeave<match_id=%s>" % [match_id]
# Send new state to a match on the server.
class MatchDataSend extends NakamaAsyncResult:
const _SCHEMA = {
"match_id": {"name": "match_id", "type": TYPE_STRING, "required": true},
"op_code": {"name": "op_code", "type": TYPE_INT, "required": true},
"presences": {"name": "presences", "type": TYPE_ARRAY, "required": false, "content": "UserPresences"},
"data": {"name": "data", "type": TYPE_STRING, "required": true},
}
var match_id : String
var presences = null
var op_code : int
var data : String
func _init(p_match_id : String, p_op_code : int, p_data : String, p_presences):
match_id = p_match_id
presences = p_presences
op_code = p_op_code
data = p_data
func serialize():
return NakamaSerializer.serialize(self)
func get_msg_key():
return "match_data_send"
func _to_string():
return "MatchDataSend<match_id=%s, op_code=%s, presences=%s, data=%s>" % [match_id, op_code, presences, data]
# Add the user to the matchmaker pool with properties.
class MatchmakerAdd extends NakamaAsyncResult:
const _SCHEMA = {
"query": {"name": "query", "type": TYPE_STRING, "required": true},
"max_count": {"name": "max_count", "type": TYPE_INT, "required": true},
"min_count": {"name": "min_count", "type": TYPE_INT, "required": true},
"numeric_properties": {"name": "numeric_properties", "type": TYPE_DICTIONARY, "required": false, "content": TYPE_REAL},
"string_properties": {"name": "string_properties", "type": TYPE_DICTIONARY, "required": false, "content": TYPE_STRING},
}
var query : String = "*"
var max_count : int = 8
var min_count : int = 2
var string_properties : Dictionary
var numeric_properties : Dictionary
func _no_set(_val):
return
func _init(p_query : String = "*", p_min_count : int = 2, p_max_count : int = 8,
p_string_props : Dictionary = Dictionary(), p_numeric_props : Dictionary = Dictionary()):
query = p_query
min_count = p_min_count
max_count = p_max_count
string_properties = p_string_props
numeric_properties = p_numeric_props
func serialize() -> Dictionary:
return NakamaSerializer.serialize(self)
func get_msg_key() -> String:
return "matchmaker_add"
func _to_string():
return "MatchmakerAdd<query=%s, max_count=%d, min_count=%d, numeric_properties=%s, string_properties=%s>" % [query, max_count, min_count, numeric_properties, string_properties]
# Remove the user from the matchmaker pool by ticket.
class MatchmakerRemove extends NakamaAsyncResult:
const _SCHEMA = {
"ticket": {"name": "ticket", "type": TYPE_STRING, "required": true}
}
var ticket : String
func _init(p_ticket : String):
ticket = p_ticket
func serialize():
return NakamaSerializer.serialize(self)
func get_msg_key() -> String:
return "matchmaker_remove"
func _to_string():
return "MatchmakerRemove<ticket=%s>" % [ticket]
# Follow one or more other users for status updates.
class StatusFollow extends NakamaAsyncResult:
const _SCHEMA = {
"user_ids": {"name": "user_ids", "type": TYPE_DICTIONARY, "required": false, "content": TYPE_STRING},
"usernames": {"name": "usernames", "type": TYPE_DICTIONARY, "required": false, "content": TYPE_STRING},
}
var user_ids := PoolStringArray()
var usernames := PoolStringArray()
func _init(p_ids : PoolStringArray, p_usernames : PoolStringArray):
user_ids = p_ids
usernames = p_usernames
func serialize():
return NakamaSerializer.serialize(self)
func get_msg_key() -> String:
return "status_follow"
func _to_string():
return "StatusFollow<user_ids=%s, usernames=%s>" % [user_ids, usernames]
# Unfollow one or more users on the server.
class StatusUnfollow extends NakamaAsyncResult:
const _SCHEMA = {
"user_ids": {"name": "user_ids", "type": TYPE_DICTIONARY, "required": false, "content": TYPE_STRING},
}
var user_ids := PoolStringArray()
func _init(p_ids : PoolStringArray):
user_ids = p_ids
func serialize():
return NakamaSerializer.serialize(self)
func get_msg_key() -> String:
return "status_unfollow"
func _to_string():
return "StatusUnfollow<user_ids=%s>" % [user_ids]
# Unfollow one or more users on the server.
class StatusUpdate extends NakamaAsyncResult:
const _SCHEMA = {
"status": {"name": "status", "type": TYPE_STRING, "required": true},
}
var status : String
func _init(p_status : String):
status = p_status
func serialize():
return NakamaSerializer.serialize(self)
func get_msg_key() -> String:
return "status_update"
func _to_string():
return "StatusUpdate<status=%s>" % [status]

View File

@ -0,0 +1,64 @@
extends NakamaAsyncResult
class_name NakamaSession
var created : bool = false setget _no_set
var token : String = "" setget _no_set
var create_time : int = 0 setget _no_set
var expire_time : int = 0 setget _no_set
var expired : bool = true setget _no_set, is_expired
var vars : Dictionary = {} setget _no_set
var username : String = "" setget _no_set
var user_id : String = "" setget _no_set
var valid : bool = false setget _no_set, is_valid
func _no_set(v):
return
func is_expired() -> bool:
return expire_time < OS.get_unix_time()
func is_valid():
return valid
func _init(p_token = null, p_created : bool = false, p_exception = null).(p_exception):
if p_token:
var unpacked = _jwt_unpack(p_token)
var decoded = {}
if not validate_json(unpacked):
decoded = parse_json(unpacked)
valid = true
if typeof(decoded) != TYPE_DICTIONARY:
decoded = {}
if decoded.empty():
valid = false
if p_exception == null:
_ex = NakamaException.new("Unable to unpack token")
token = p_token
created = p_created
create_time = OS.get_unix_time()
expire_time = int(decoded.get("exp", 0))
username = str(decoded.get("usn", ""))
user_id = str(decoded.get("uid", ""))
if decoded.has("vrs") and typeof(decoded["vrs"]) == TYPE_DICTIONARY:
for k in decoded["vrs"]:
vars[k] = decoded["vrs"][k]
func _to_string():
if is_exception():
return get_exception()._to_string()
return "Session<created=%s, token=%s, create_time=%d, username=%s, user_id=%s, vars=%s>" % [
created, token, create_time, username, user_id, str(vars)]
func _jwt_unpack(p_token : String) -> String:
# Hack decode JSON payload from JWT.
if p_token.find(".") == -1:
return ""
var payload = p_token.split('.')[1];
var pad_length = ceil(payload.length() / 4.0) * 4;
# Pad base64
for i in range(0, pad_length - payload.length()):
payload += "="
payload = payload.replace("-", "+").replace("_", "/")
return Marshalls.base64_to_utf8(payload)

View File

@ -0,0 +1,34 @@
extends Reference
class_name NakamaStorageObjectId
# The collection which stores the object.
var collection : String
# The key of the object within the collection.
var key : String
# The user owner of the object.
var user_id : String
# The version hash of the object.
var version : String
func _init(p_collection, p_key, p_user_id = "", p_version = ""):
collection = p_collection
key = p_key
user_id = p_user_id
version = p_version
func as_delete():
return NakamaAPI.ApiDeleteStorageObjectId.create(NakamaAPI, {
"collection": collection,
"key": key,
"version": version
})
func as_read():
return NakamaAPI.ApiReadStorageObjectId.create(NakamaAPI, {
"collection": collection,
"key": key,
"user_id": user_id
})

View File

@ -0,0 +1,28 @@
extends Reference
class_name NakamaWriteStorageObject
var collection : String
var key : String
var permission_read : int = 0
var permission_write : int = 0
var value : String
var version : String
func _init(p_collection : String, p_key : String, p_permission_read : int,
p_permission_write : int, p_value : String, p_version : String):
collection = p_collection
key = p_key
permission_read = p_permission_read
permission_write = p_permission_write
value = p_value
version = p_version
func as_write():
return NakamaAPI.ApiWriteStorageObject.create(NakamaAPI, {
"collection": collection,
"key": key,
"permission_read": permission_read,
"permission_write": permission_write,
"value": value,
"version": version
})

View File

@ -0,0 +1,795 @@
extends Reference
# A client for the API in Nakama server.
class_name NakamaClient
const ChannelType = NakamaRTMessage.ChannelJoin.ChannelType
func _no_set(_p):
return
func _no_get():
return null
# The host address of the server. Defaults to "127.0.0.1".
var host : String setget _no_set
# The port number of the server. Defaults to 7350.
var port : int setget _no_set
# The protocol scheme used to connect with the server. Must be either "http" or "https".
var scheme : String setget _no_set
# The key used to authenticate with the server without a session. Defaults to "defaultkey".
var server_key : String = "defaultkey" setget _no_set
# Set the timeout in seconds on requests sent to the server.
var timeout : int
var logger : NakamaLogger = null
var _api_client := NakamaAPI.ApiClient.new("", NakamaAPI, null) setget _no_set, _no_get
func _init(p_adapter : NakamaHTTPAdapter,
p_server_key : String,
p_scheme : String,
p_host : String,
p_port : int,
p_timeout : int):
server_key = p_server_key
scheme = p_scheme
host = p_host
port = p_port
timeout = p_timeout
logger = p_adapter.logger
_api_client = NakamaAPI.ApiClient.new(scheme + "://" + host + ":" + str(port), p_adapter, NakamaAPI, p_timeout)
# Restore a session from the auth token.
# A `null` or empty authentication token will return `null`.
# @param authToken - The authentication token to restore as a session.
# Returns a session.
static func restore_session(auth_token : String):
return NakamaSession.new(auth_token, false)
func _to_string():
return "Client(Host='%s', Port=%s, Scheme='%s', ServerKey='%s', Timeout=%s)" % [
host, port, scheme, server_key, timeout
]
func _parse_auth(p_session) -> NakamaSession:
if p_session.is_exception():
return NakamaSession.new(null, false, p_session.get_exception())
return NakamaSession.new(p_session.token, p_session.created)
# Add one or more friends by id or username.
# @param p_session - The session of the user.
# @param p_ids - The ids of the users to add or invite as friends.
# @param p_usernames - The usernames of the users to add as friends.
# Returns a task which represents the asynchronous operation.
func add_friends_async(p_session : NakamaSession, p_ids = null, p_usernames = null) -> NakamaAsyncResult:
return _api_client.add_friends_async(p_session.token, p_ids, p_usernames)
# Add one or more users to the group.
# @param p_session - The session of the user.
# @param p_group_id - The id of the group to add users into.
# @param p_ids - The ids of the users to add or invite to the group.
# Returns a task which represents the asynchronous operation.
func add_group_users_async(p_session : NakamaSession, p_group_id : String, p_ids : PoolStringArray) -> NakamaAsyncResult:
return _api_client.add_group_users_async(p_session.token, p_group_id, p_ids);
# Authenticate a user with a custom id.
# @param p_id - A custom identifier usually obtained from an external authentication service.
# @param p_username - A username used to create the user. May be `null`.
# @param p_create - If the user should be created when authenticated.
# @param p_vars - Extra information that will be bundled in the session token.
# Returns a task which resolves to a session object.
func authenticate_custom_async(p_id : String, p_username = null, p_create : bool = true, p_vars = null) -> NakamaSession:
return _parse_auth(yield(_api_client.authenticate_custom_async(server_key, "",
NakamaAPI.ApiAccountCustom.create(NakamaAPI, {
"id": p_id,
"vars": p_vars
}), p_create, p_username), "completed"))
# Authenticate a user with a device id.
# @param p_id - A device identifier usually obtained from a platform API.
# @param p_username - A username used to create the user. May be `null`.
# @param p_create - If the user should be created when authenticated.
# @param p_vars - Extra information that will be bundled in the session token.
# Returns a task which resolves to a session object.
func authenticate_device_async(p_id : String, p_username = null, p_create : bool = true, p_vars = null) -> NakamaSession:
return _parse_auth(yield(_api_client.authenticate_device_async(server_key, "",
NakamaAPI.ApiAccountDevice.create(NakamaAPI, {
"id": p_id,
"vars": p_vars
}), p_create, p_username), "completed"))
# Authenticate a user with an email and password.
# @param p_email - The email address of the user.
# @param p_password - The password for the user.
# @param p_username - A username used to create the user. May be `null`.
# @param p_create - If the user should be created when authenticated.
# @param p_vars - Extra information that will be bundled in the session token.
# Returns a task which resolves to a session object.
func authenticate_email_async(p_email : String, p_password : String, p_username = null, p_create : bool = true, p_vars = null) -> NakamaSession:
return _parse_auth(yield(_api_client.authenticate_email_async(server_key, "",
NakamaAPI.ApiAccountEmail.create(NakamaAPI, {
"email": p_email,
"password": p_password,
"vars": p_vars
}), p_create, p_username), "completed"))
# Authenticate a user with a Facebook auth token.
# @param p_token - An OAuth access token from the Facebook SDK.
# @param p_username - A username used to create the user. May be `null`.
# @param p_create - If the user should be created when authenticated.
# @param p_import - If the Facebook friends should be imported.
# @param p_vars - Extra information that will be bundled in the session token.
# Returns a task which resolves to a session object.
func authenticate_facebook_async(p_token : String, p_username = null, p_create : bool = true, p_import : bool = true, p_vars = null) -> NakamaSession:
return _parse_auth(yield(_api_client.authenticate_facebook_async(server_key, "",
NakamaAPI.ApiAccountFacebook.create(NakamaAPI, {
"token": p_token,
"vars": p_vars
}), p_create, p_username, p_import), "completed"))
# Authenticate a user with a Facebook Instant Game token against the server.
# @param p_signed_player_info - Facebook Instant Game signed info from Facebook SDK.
# @param p_username - A username used to create the user. May be `null`.
# @param p_create - If the user should be created when authenticated.
# @param p_import - If the Facebook friends should be imported.
# @param p_vars - Extra information that will be bundled in the session token.
# Returns a task which resolves to a session object.
func authenticate_facebook_instant_game_async(p_signed_player_info : String, p_username = null, p_create : bool = true, p_vars = null) -> NakamaSession:
return _parse_auth(yield(_api_client.authenticate_facebook_instant_game_async(server_key, "",
NakamaAPI.ApiAccountFacebookInstantGame.create(NakamaAPI, {
"signed_player_info": p_signed_player_info,
"vars": p_vars
}), p_create, p_username), "completed"))
# Authenticate a user with Apple Game Center.
# @param p_bundle_id - The bundle id of the Game Center application.
# @param p_player_id - The player id of the user in Game Center.
# @param p_public_key_url - The URL for the public encryption key.
# @param p_salt - A random `NSString` used to compute the hash and keep it randomized.
# @param p_signature - The verification signature data generated.
# @param p_timestamp_seconds - The date and time that the signature was created.
# @param p_username - A username used to create the user. May be `null`.
# @param p_create - If the user should be created when authenticated.
# @param p_vars - Extra information that will be bundled in the session token.
# Returns a task which resolves to a session object.
func authenticate_game_center_async(p_bundle_id : String, p_player_id : String, p_public_key_url : String,
p_salt : String, p_signature : String, p_timestamp_seconds : String, p_username = null, p_create : bool = true, p_vars = null) -> NakamaSession:
return _parse_auth(yield(_api_client.authenticate_game_center_async(server_key, "",
NakamaAPI.ApiAccountGameCenter.create(NakamaAPI, {
"bundle_id": p_bundle_id,
"player_id": p_player_id,
"public_key_url": p_public_key_url,
"salt": p_salt,
"signature": p_signature,
"timestamp_seconds": p_timestamp_seconds,
"vars": p_vars
}), p_create, p_username), "completed"))
# Authenticate a user with a Google auth token.
# @param p_token - An OAuth access token from the Google SDK.
# @param p_username - A username used to create the user. May be `null`.
# @param p_create - If the user should be created when authenticated.
# @param p_vars - Extra information that will be bundled in the session token.
# Returns a task which resolves to a session object.
func authenticate_google_async(p_token : String, p_username = null, p_create : bool = true, p_vars = null) -> NakamaSession:
return _parse_auth(yield(_api_client.authenticate_google_async(server_key, "",
NakamaAPI.ApiAccountGoogle.create(NakamaAPI, {
"token": p_token,
"vars": p_vars
}), p_create, p_username), "completed"))
# Authenticate a user with a Steam auth token.
# @param p_token - An authentication token from the Steam network.
# @param p_username - A username used to create the user. May be `null`.
# @param p_create - If the user should be created when authenticated.
# @param p_vars - Extra information that will be bundled in the session token.
# Returns a task which resolves to a session object.
func authenticate_steam_async(p_token : String, p_username = null, p_create : bool = true, p_vars = null) -> NakamaSession:
return _parse_auth(yield(_api_client.authenticate_steam_async(server_key, "",
NakamaAPI.ApiAccountSteam.create(NakamaAPI, {
"token": p_token,
"vars": p_vars
}), p_create, p_username), "completed"))
# Block one or more friends by id or username.
# @param p_session - The session of the user.
# @param p_ids - The ids of the users to block.
# @param p_usernames - The usernames of the users to block.
# Returns a task which represents the asynchronous operation.
func block_friends_async(p_session : NakamaSession, p_ids : PoolStringArray, p_usernames = null) -> NakamaAsyncResult:
return _api_client.block_friends_async(p_session.token, p_ids, p_usernames);
# Create a group.
# @param p_session - The session of the user.
# @param p_name - The name for the group.
# @param p_description - A description for the group.
# @param p_avatar_url - An avatar url for the group.
# @param p_lang_tag - A language tag in BCP-47 format for the group.
# @param p_open - If the group should have open membership.
# @param p_max_count - The maximum number of members allowed.
# Returns a task which resolves to a new group object.
func create_group_async(p_session : NakamaSession, p_name : String, p_description : String = "",
p_avatar_url = null, p_lang_tag = null, p_open : bool = true, p_max_count : int = 100): # -> NakamaAPI.ApiGroup:
return _api_client.create_group_async(p_session.token,
NakamaAPI.ApiCreateGroupRequest.create(NakamaAPI, {
"avatar_url": p_avatar_url,
"description": p_description,
"lang_tag": p_lang_tag,
"max_count": p_max_count,
"name": p_name,
"open": p_open
}))
# Delete one more or users by id or username from friends.
# @param p_session - The session of the user.
# @param p_ids - The user ids to remove as friends.
# @param p_usernames - The usernames to remove as friends.
# Returns a task which represents the asynchronous operation.
func delete_friends_async(p_session : NakamaSession, p_ids : PoolStringArray, p_usernames = null) -> NakamaAsyncResult:
return _api_client.delete_friends_async(p_session.token, p_ids, p_usernames)
# Delete a group by id.
# @param p_session - The session of the user.
# @param p_group_id - The group id to to remove.
# Returns a task which represents the asynchronous operation.
func delete_group_async(p_session : NakamaSession, p_group_id : String) -> NakamaAsyncResult:
return _api_client.delete_group_async(p_session.token, p_group_id)
# Delete a leaderboard record.
# @param p_session - The session of the user.
# @param p_leaderboard_id - The id of the leaderboard with the record to be deleted.
# Returns a task which represents the asynchronous operation.
func delete_leaderboard_record_async(p_session : NakamaSession, p_leaderboard_id : String) -> NakamaAsyncResult:
return _api_client.delete_leaderboard_record_async(p_session.token, p_leaderboard_id)
# Delete one or more notifications by id.
# @param p_session - The session of the user.
# @param p_ids - The notification ids to remove.
# Returns a task which represents the asynchronous operation.
func delete_notifications_async(p_session : NakamaSession, p_ids : PoolStringArray) -> NakamaAsyncResult:
return _api_client.delete_notifications_async(p_session.token, p_ids)
# Delete one or more storage objects.
# @param p_session - The session of the user.
# @param p_ids - The ids of the objects to delete.
# Returns a task which represents the asynchronous operation.
func delete_storage_objects_async(p_session : NakamaSession, p_ids : Array) -> NakamaAsyncResult:
var ids : Array = []
for id in p_ids:
if not id is NakamaStorageObjectId:
continue # TODO Exceptions
var obj_id : NakamaStorageObjectId = id
ids.append(obj_id.as_delete().serialize())
return _api_client.delete_storage_objects_async(p_session.token,
NakamaAPI.ApiDeleteStorageObjectsRequest.create(NakamaAPI, {
"object_ids": ids
}))
# Fetch the user account owned by the session.
# @param p_session - The session of the user.
# Returns a task which resolves to the account object.
func get_account_async(p_session : NakamaSession): # -> NakamaAPI.ApiAccount:
return _api_client.get_account_async(p_session.token)
# Fetch one or more users by id, usernames, and Facebook ids.
# @param p_session - The session of the user.
# @param p_ids - The IDs of the users to retrieve.
# @param p_usernames - The usernames of the users to retrieve.
# @param p_facebook_ids - The facebook IDs of the users to retrieve.
# Returns a task which resolves to a collection of user objects.
func get_users_async(p_session : NakamaSession, p_ids : PoolStringArray, p_usernames = null, p_facebook_ids = null): # -> NakamaAPI.ApiUsers:
return _api_client.get_users_async(p_session.token, p_ids, p_usernames, p_facebook_ids)
# Import Facebook friends and add them to the user's account.
# The server will import friends when the user authenticates with Facebook. This function can be used to be
# explicit with the import operation.
# @param p_session - The session of the user.
# @param p_token - An OAuth access token from the Facebook SDK.
# @param p_reset - If the Facebook friend import for the user should be reset.
# Returns a task which represents the asynchronous operation.
func import_facebook_friends_async(p_session : NakamaSession, p_token : String, p_reset = null) -> NakamaAsyncResult:
return _api_client.import_facebook_friends_async(p_session.token,
NakamaAPI.ApiAccountFacebook.create(NakamaAPI, {
"token": p_token
}), p_reset)
# Join a group if it has open membership or request to join it.
# @param p_session - The session of the user.
# @param p_group_id - The ID of the group to join.
# Returns a task which represents the asynchronous operation.
func join_group_async(p_session : NakamaSession, p_group_id : String) -> NakamaAsyncResult:
return _api_client.join_group_async(p_session.token, p_group_id)
# Join a tournament by ID.
# @param p_session - The session of the user.
# @param p_tournament_id - The ID of the tournament to join.
# Returns a task which represents the asynchronous operation.
func join_tournament_async(p_session : NakamaSession, p_tournament_id : String) -> NakamaAsyncResult:
return _api_client.join_tournament_async(p_session.token, p_tournament_id)
# Kick one or more users from the group.
# @param p_session - The session of the user.
# @param p_group_id - The ID of the group.
# @param p_ids - The IDs of the users to kick.
# Returns a task which represents the asynchronous operation.
func kick_group_users_async(p_session : NakamaSession, p_group_id : String, p_ids : PoolStringArray) -> NakamaAsyncResult:
return _api_client.kick_group_users_async(p_session.token, p_group_id, p_ids)
# Leave a group by ID.
# @param p_session - The session of the user.
# @param p_group_id - The ID of the group to leave.
# Returns a task which represents the asynchronous operation.
func leave_group_async(p_session : NakamaSession, p_group_id : String) -> NakamaAsyncResult:
return _api_client.leave_group_async(p_session.token, p_group_id)
# Link a custom ID to the user account owned by the session.
# @param p_session - The session of the user.
# @param p_id - A custom identifier usually obtained from an external authentication service.
# Returns a task which represents the asynchronous operation.
func link_custom_async(p_session : NakamaSession, p_id : String) -> NakamaAsyncResult:
return _api_client.link_custom_async(p_session.token, NakamaAPI.ApiAccountCustom.create(NakamaAPI, {
"id": p_id
}))
# Link a device ID to the user account owned by the session.
# @param p_session - The session of the user.
# @param p_id - A device identifier usually obtained from a platform API.
# Returns a task which represents the asynchronous operation.
func link_device_async(p_session : NakamaSession, p_id : String) -> NakamaAsyncResult:
return _api_client.link_device_async(p_session.token, NakamaAPI.ApiAccountDevice.create(NakamaAPI, {
"id": p_id
}))
# Link an email with password to the user account owned by the session.
# @param p_session - The session of the user.
# @param p_email - The email address of the user.
# @param p_password - The password for the user.
# Returns a task which represents the asynchronous operation.
func link_email_async(p_session : NakamaSession, p_email : String, p_password : String) -> NakamaAsyncResult:
return _api_client.link_email_async(p_session.token, NakamaAPI.ApiAccountEmail.create(NakamaAPI, {
"email": p_email,
"password": p_password
}))
# Link a Facebook profile to a user account.
# @param p_session - The session of the user.
# @param p_token - An OAuth access token from the Facebook SDK.
# @param p_import - If the Facebook friends should be imported.
# Returns a task which represents the asynchronous operation.
func link_facebook_async(p_session : NakamaSession, p_token : String) -> NakamaAsyncResult:
return _api_client.link_facebook_async(p_session.token, NakamaAPI.ApiAccountFacebook.create(NakamaAPI, {
"token": p_token
}))
# Add Facebook Instant Game to the social profiles on the current user's account.
# @param p_session - The session of the user.
# @param p_token - An OAuth access token from the Facebook SDK.
# @param p_import - If the Facebook friends should be imported.
# Returns a task which represents the asynchronous operation.
func link_facebook_instant_game_async(p_session : NakamaSession, p_signed_player_info : String) -> NakamaAsyncResult:
return _api_client.link_facebook_instant_game_async(
p_session.token,
NakamaAPI.ApiAccountFacebookInstantGame.create(
NakamaAPI, {
"signed_player_info": p_signed_player_info
})
)
# Link a Game Center profile to a user account.
# @param p_session - The session of the user.
# @param p_bundle_id - The bundle ID of the Game Center application.
# @param p_player_id - The player ID of the user in Game Center.
# @param p_public_key_url - The URL for the public encryption key.
# @param p_salt - A random `NSString` used to compute the hash and keep it randomized.
# @param p_signature - The verification signature data generated.
# @param p_timestamp_seconds - The date and time that the signature was created.
# Returns a task which represents the asynchronous operation.
func link_game_center_async(p_session : NakamaSession,
p_bundle_id : String, p_player_id : String, p_public_key_url : String, p_salt : String, p_signature : String, p_timestamp_seconds) -> NakamaAsyncResult:
return _api_client.link_game_center_async(p_session.token,
NakamaAPI.ApiAccountGameCenter.create(NakamaAPI, {
"bundle_id": p_bundle_id,
"player_id": p_player_id,
"public_key_url": p_public_key_url,
"salt": p_salt,
"signature": p_signature,
"timestamp_seconds": p_timestamp_seconds,
}))
# Link a Google profile to a user account.
# @param p_session - The session of the user.
# @param p_token - An OAuth access token from the Google SDK.
# Returns a task which represents the asynchronous operation.
func link_google_async(p_session : NakamaSession, p_token : String) -> NakamaAsyncResult:
return _api_client.link_google_async(p_session.token, NakamaAPI.ApiAccountGoogle.create(NakamaAPI, {
"token": p_token
}))
# Link a Steam profile to a user account.
# @param p_session - The session of the user.
# @param p_token - An authentication token from the Steam network.
# Returns a task which represents the asynchronous operation.
func link_steam_async(p_session : NakamaSession, p_token : String) -> NakamaAsyncResult:
return _api_client.link_steam_async(p_session.token, NakamaAPI.ApiAccountSteam.create(NakamaAPI, {
"token": p_token
}))
# List messages from a chat channel.
# @param p_session - The session of the user.
# @param p_channel_id - The id of the chat channel.
# @param p_limit - The number of chat messages to list.
# @param forward - Fetch messages forward from the current cursor (or the start).
# @param p_cursor - A cursor for the current position in the messages history to list.
# Returns a task which resolves to the channel message list object.
func list_channel_messages_async(p_session : NakamaSession, p_channel_id : String, limit : int = 1,
forward : bool = true, cursor = null): # -> NakamaAPI.ApiChannelMessageList:
return _api_client.list_channel_messages_async(p_session.token, p_channel_id, limit, forward, cursor)
# List of friends of the current user.
# @param p_session - The session of the user.
# @param p_state - Filter by friendship state.
# @param p_limit - The number of friends to list.
# @param p_cursor - A cursor for the current position in the friends list.
# Returns a task which resolves to the friend objects.
func list_friends_async(p_session : NakamaSession, p_state = null, p_limit = null, p_cursor = null): # -> NakamaAPI.ApiFriendList:
return _api_client.list_friends_async(p_session.token, p_limit, p_state, p_cursor)
# List all users part of the group.
# @param p_session - The session of the user.
# @param p_group_id - The ID of the group.
# @param p_state - Filter by group membership state.
# @param p_limit - The number of groups to list.
# @param p_cursor - A cursor for the current position in the group listing.
# Returns a task which resolves to the group user objects.
func list_group_users_async(p_session : NakamaSession, p_group_id : String, p_state = null, p_limit = null, p_cursor = null): # -> NakamaAPI.ApiGroupUserList:
return _api_client.list_group_users_async(p_session.token, p_group_id, p_limit, p_state, p_cursor)
# List groups on the server.
# @param p_session - The session of the user.
# @param p_name - The name filter to apply to the group list.
# @param p_limit - The number of groups to list.
# @param p_cursor - A cursor for the current position in the groups to list.
# Returns a task to resolve group objects.
func list_groups_async(p_session : NakamaSession, p_name = null, p_limit : int = 10, p_cursor = null): # -> NakamaAPI.ApiGroupList:
return _api_client.list_groups_async(p_session.token, p_name, p_cursor, p_limit)
# List records from a leaderboard.
# @param p_session - The session of the user.
# @param p_leaderboard_id - The ID of the leaderboard to list.
# @param p_owner_ids - Record owners to fetch with the list of records.
# @param p_expiry - Expiry in seconds (since epoch) to begin fetching records from. Optional. 0 means from current time.
# @param p_limit - The number of records to list.
# @param p_cursor - A cursor for the current position in the leaderboard records to list.
# Returns a task which resolves to the leaderboard record objects.
func list_leaderboard_records_async(p_session : NakamaSession,
p_leaderboard_id : String, p_owner_ids = null, p_expiry = null, p_limit : int = 10, p_cursor = null): # -> NakamaAPI.ApiLeaderboardRecordList:
return _api_client.list_leaderboard_records_async(p_session.token,
p_leaderboard_id, p_owner_ids, p_limit, p_cursor, p_expiry)
# List leaderboard records that belong to a user.
# @param p_session - The session for the user.
# @param p_leaderboard_id - The ID of the leaderboard to list.
# @param p_owner_id - The ID of the user to list around.
# @param p_expiry - Expiry in seconds (since epoch) to begin fetching records from. Optional. 0 means from current time.
# @param p_limit - The limit of the listings.
# Returns a task which resolves to the leaderboard record objects.
func list_leaderboard_records_around_owner_async(p_session : NakamaSession,
p_leaderboar_id : String, p_owner_id : String, p_expiry = null, p_limit : int = 10): # -> NakamaAPI.ApiLeaderboardRecordList:
return _api_client.list_leaderboard_records_around_owner_async(p_session.token,
p_leaderboar_id, p_owner_id, p_limit, p_expiry)
# Fetch a list of matches active on the server.
# @param p_session - The session of the user.
# @param p_min - The minimum number of match participants.
# @param p_max - The maximum number of match participants.
# @param p_limit - The number of matches to list.
# @param p_authoritative - If authoritative matches should be included.
# @param p_label - The label to filter the match list on.
# @param p_query - A query for the matches to filter.
# Returns a task which resolves to the match list object.
func list_matches_async(p_session : NakamaSession, p_min : int, p_max : int, p_limit : int, p_authoritative : bool,
p_label : String, p_query : String): # -> NakamaAPI.ApiMatchList:
return _api_client.list_matches_async(p_session.token, p_limit, p_authoritative, p_label, p_min, p_max, p_query)
# List notifications for the user with an optional cursor.
# @param p_session - The session of the user.
# @param p_limit - The number of notifications to list.
# @param p_cacheable_cursor - A cursor for the current position in notifications to list.
# Returns a task to resolve notifications objects.
func list_notifications_async(p_session : NakamaSession, p_limit : int = 10, p_cacheable_cursor = null): # -> NakamaAPI.ApiNotificationList:
return _api_client.list_notifications_async(p_session.token, p_limit, p_cacheable_cursor)
# List storage objects in a collection which have public read access.
# @param p_session - The session of the user.
# @param p_collection - The collection to list over.
# @param p_user_id - The id of the user that owns the objects.
# @param p_limit - The number of objects to list.
# @param p_cursor - A cursor to paginate over the collection.
# Returns a task which resolves to the storage object list.
func list_storage_objects_async(p_session : NakamaSession, p_collection : String, p_user_id : String = "", p_limit : int = 10, p_cursor = null): # -> NakamaAPI.ApiStorageObjectList:
# List tournament records around the owner.
return _api_client.list_storage_objects_async(p_session.token, p_collection, p_user_id, p_limit, p_cursor)
# List tournament records around the owner.
# @param p_session - The session of the user.
# @param p_tournament_id - The ID of the tournament.
# @param p_owner_id - The ID of the owner to pivot around.
# @param p_expiry - Expiry in seconds (since epoch) to begin fetching records from.
# @param p_limit - The number of records to list.
# Returns a task which resolves to the tournament record list object.
func list_tournament_records_around_owner_async(p_session : NakamaSession,
p_tournament_id : String, p_owner_id : String, p_limit : int = 10, p_expiry = null): # -> NakamaAPI.ApiTournamentRecordList:
return _api_client.list_tournament_records_around_owner_async(p_session.token, p_tournament_id, p_owner_id, p_limit, p_expiry)
# List records from a tournament.
# @param p_session - The session of the user.
# @param p_tournament_id - The ID of the tournament.
# @param p_owner_ids - The IDs of the record owners to return in the result.
# @param p_expiry - Expiry in seconds (since epoch) to begin fetching records from.
# @param p_limit - The number of records to list.
# @param p_cursor - An optional cursor for the next page of tournament records.
# Returns a task which resolves to the list of tournament records.
func list_tournament_records_async(p_session : NakamaSession, p_tournament_id : String,
p_owner_ids = null, p_limit : int = 10, p_cursor = null, p_expiry = null): # -> NakamaAPI.ApiTournamentRecordList:
return _api_client.list_tournament_records_async(p_session.token, p_tournament_id, p_owner_ids, p_limit, p_cursor, p_expiry)
# List current or upcoming tournaments.
# @param p_session - The session of the user.
# @param p_category_start - The start of the category of tournaments to include.
# @param p_category_end - The end of the category of tournaments to include.
# @param p_start_time - The start time of the tournaments. (UNIX timestamp)
# @param p_end_time - The end time of the tournaments. (UNIX timestamp)
# @param p_limit - The number of tournaments to list.
# @param p_cursor - An optional cursor for the next page of tournaments.
# Returns a task which resolves to the list of tournament objects.
func list_tournaments_async(p_session : NakamaSession, p_category_start : int, p_category_end : int,
p_start_time : int, p_end_time : int, p_limit : int = 10, p_cursor = null): # -> NakamaAPI.ApiTournamentList:
return _api_client.list_tournaments_async(p_session.token,
p_category_start, p_category_end, p_start_time, p_end_time, p_limit, p_cursor)
# List of groups the current user is a member of.
# @param p_session - The session of the user.
# @param p_user_id - The ID of the user whose groups to list.
# @param p_state - Filter by group membership state.
# @param p_limit - The number of records to list.
# @param p_cursor - A cursor for the current position in the listing.
# Returns a task which resolves to the group list object.
func list_user_groups_async(p_session : NakamaSession, p_user_id : String, p_state = null, p_limit = null, p_cursor = null): # -> NakamaAPI.ApiUserGroupList:
return _api_client.list_user_groups_async(p_session.token, p_user_id, p_limit, p_state, p_cursor)
# List storage objects in a collection which belong to a specific user and have public read access.
# @param p_session - The session of the user.
# @param p_collection - The collection to list over.
# @param p_user_id - The user ID of the user to list objects for.
# @param p_limit - The number of objects to list.
# @param p_cursor - A cursor to paginate over the collection.
# Returns a task which resolves to the storage object list.
func list_users_storage_objects_async(p_session : NakamaSession,
p_collection : String, p_user_id : String, p_limit : int, p_cursor : String): # -> NakamaAPI.ApiStorageObjectList:
return _api_client.list_storage_objects2_async(p_session.token, p_collection, p_user_id, p_limit, p_cursor)
# Promote one or more users in the group.
# @param p_session - The session of the user.
# @param p_group_id - The ID of the group to promote users into.
# @param p_ids - The IDs of the users to promote.
# Returns a task which represents the asynchronous operation.
func promote_group_users_async(p_session : NakamaSession, p_group_id : String, p_ids : PoolStringArray) -> NakamaAsyncResult:
return _api_client.promote_group_users_async(p_session.token, p_group_id, p_ids)
# Read one or more objects from the storage engine.
# @param p_session - The session of the user.
# @param p_ids - The objects to read.
# Returns a task which resolves to the storage batch object.
func read_storage_objects_async(p_session : NakamaSession, p_ids : Array): # -> NakamaAPI.ApiStorageObjects:
var ids = []
for id in p_ids:
if not id is NakamaStorageObjectId:
continue # TODO Exceptions
var obj_id : NakamaStorageObjectId = id
ids.append(obj_id.as_read().serialize())
return _api_client.read_storage_objects_async(p_session.token,
NakamaAPI.ApiReadStorageObjectsRequest.create(NakamaAPI, {
"object_ids": ids
}))
# Execute a function with an input payload on the server.
# @param p_session - The session of the user.
# @param p_id - The ID of the function to execute on the server.
# @param p_payload - The payload to send with the function call.
# Returns a task which resolves to the RPC response.
func rpc_async(p_session : NakamaSession, p_id : String, p_payload : String = ""): # -> NakamaAPI.ApiRpc:
return _api_client.rpc_func_async(p_session.token, p_id, p_payload)
# Execute a function on the server without a session.
# This function is usually used with server side code. DO NOT USE client side.
# @param p_http_key - The secure HTTP key used to authenticate.
# @param p_id - The id of the function to execute on the server.
# @param p_payload - A payload to send with the function call.
# Returns a task to resolve an RPC response.
func rpc_async_with_key(p_http_key : String, p_id : String, p_payload = null): # -> NakamaAPI.ApiRpc:
return _api_client.rpc_func2_async("", p_id, p_payload, p_http_key)
# Unlink a custom ID from the user account owned by the session.
# @param p_session - The session of the user.
# @param p_id - A custom identifier usually obtained from an external authentication service.
# Returns a task which represents the asynchronous operation.
func unlink_custom_async(p_session : NakamaSession, p_id : String) -> NakamaAsyncResult:
return _api_client.unlink_custom_async(p_session.token, NakamaAPI.ApiAccountCustom.create(NakamaAPI, {
"id": p_id
}))
# Unlink a device ID from the user account owned by the session.
# @param p_session - The session of the user.
# @param p_id - A device identifier usually obtained from a platform API.
# Returns a task which represents the asynchronous operation.
func unlink_device_async(p_session : NakamaSession, p_id : String) -> NakamaAsyncResult:
return _api_client.unlink_device_async(p_session.token, NakamaAPI.ApiAccountDevice.create(NakamaAPI, {
"id": p_id
}))
# Unlink an email with password from the user account owned by the session.
# @param p_session - The session of the user.
# @param p_email - The email address of the user.
# @param p_password - The password for the user.
# Returns a task which represents the asynchronous operation.
func unlink_email_async(p_session : NakamaSession, p_email : String, p_password : String) -> NakamaAsyncResult:
return _api_client.unlink_email_async(p_session.token, NakamaAPI.ApiAccountEmail.create(NakamaAPI, {
"email": p_email,
"password": p_password
}))
# Unlink a Facebook profile from the user account owned by the session.
# @param p_session - The session of the user.
# @param p_token - An OAuth access token from the Facebook SDK.
# Returns a task which represents the asynchronous operation.
func unlink_facebook_async(p_session : NakamaSession, p_token : String) -> NakamaAsyncResult:
return _api_client.unlink_facebook_async(p_session.token, NakamaAPI.ApiAccountFacebook.create(NakamaAPI, {
"token": p_token
}))
# Unlink a Facebook profile from the user account owned by the session.
# @param p_session - The session of the user.
# @param p_token - An OAuth access token from the Facebook SDK.
# Returns a task which represents the asynchronous operation.
func unlink_facebook_instant_game_async(p_session : NakamaSession, p_signed_player_info : String) -> NakamaAsyncResult:
return _api_client.unlink_facebook_instant_game_async(
p_session.token,
NakamaAPI.ApiAccountFacebookInstantGame.create(NakamaAPI, {
"signed_player_info": p_signed_player_info
})
)
# Unlink a Game Center profile from the user account owned by the session.
# @param p_session - The session of the user.
# @param p_bundle_id - The bundle ID of the Game Center application.
# @param p_player_id - The player ID of the user in Game Center.
# @param p_public_key_url - The URL for the public encryption key.
# @param p_salt - A random `NSString` used to compute the hash and keep it randomized.
# @param p_signature - The verification signature data generated.
# @param p_timestamp_seconds - The date and time that the signature was created.
# Returns a task which represents the asynchronous operation.
func unlink_game_center_async(p_session : NakamaSession,
p_bundle_id : String, p_player_id : String, p_public_key_url : String, p_salt : String, p_signature : String, p_timestamp_seconds) -> NakamaAsyncResult:
return _api_client.unlink_game_center_async(p_session.token,
NakamaAPI.ApiAccountGameCenter.create(NakamaAPI, {
"bundle_id": p_bundle_id,
"player_id": p_player_id,
"public_key_url": p_public_key_url,
"salt": p_salt,
"signature": p_signature,
"timestamp_seconds": p_timestamp_seconds,
}))
# Unlink a Google profile from the user account owned by the session.
# @param p_session - The session of the user.
# @param p_token - An OAuth access token from the Google SDK.
# Returns a task which represents the asynchronous operation.
func unlink_google_async(p_session : NakamaSession, p_token : String) -> NakamaAsyncResult:
return _api_client.unlink_google_async(p_session.token, NakamaAPI.ApiAccountGoogle.create(NakamaAPI, {
"token": p_token
}))
# Unlink a Steam profile from the user account owned by the session.
# @param p_session - The session of the user.
# @param p_token - An authentication token from the Steam network.
# Returns a task which represents the asynchronous operation.
func unlink_steam_async(p_session : NakamaSession, p_token : String) -> NakamaAsyncResult:
return _api_client.unlink_steam_async(p_session.token, NakamaAPI.ApiAccountSteam.create(NakamaAPI, {
"token": p_token
}))
# Update the current user's account on the server.
# @param p_session - The session for the user.
# @param p_username - The new username for the user.
# @param p_display_name - A new display name for the user.
# @param p_avatar_url - A new avatar url for the user.
# @param p_lang_tag - A new language tag in BCP-47 format for the user.
# @param p_location - A new location for the user.
# @param p_timezone - New timezone information for the user.
# Returns a task which represents the asynchronous operation.
func update_account_async(p_session : NakamaSession, p_username = null, p_display_name = null,
p_avatar_url = null, p_lang_tag = null, p_location = null, p_timezone = null) -> NakamaAsyncResult:
return _api_client.update_account_async(p_session.token,
NakamaAPI.ApiUpdateAccountRequest.create(NakamaAPI, {
"avatar_url": p_avatar_url,
"display_name": p_display_name,
"lang_tag": p_lang_tag,
"location": p_location,
"timezone": p_timezone,
"username": p_username
}))
# Update a group.
# The user must have the correct access permissions for the group.
# @param p_session - The session of the user.
# @param p_group_id - The ID of the group to update.
# @param p_name - A new name for the group.
# @param p_open - If the group should have open membership.
# @param p_description - A new description for the group.
# @param p_avatar_url - A new avatar url for the group.
# @param p_lang_tag - A new language tag in BCP-47 format for the group.
# Returns a task which represents the asynchronous operation.
func update_group_async(p_session : NakamaSession,
p_group_id : String, p_name = null, p_description = null, p_avatar_url = null, p_lang_tag = null, p_open = null) -> NakamaAsyncResult:
return _api_client.update_group_async(p_session.token, p_group_id,
NakamaAPI.ApiUpdateGroupRequest.create(NakamaAPI, {
"name": p_name,
"open": p_open,
"avatar_url": p_avatar_url,
"description": p_description,
"lang_tag": p_lang_tag
}))
# Write a record to a leaderboard.
# @param p_session - The session for the user.
# @param p_leaderboard_id - The ID of the leaderboard to write.
# @param p_score - The score for the leaderboard record.
# @param p_subscore - The subscore for the leaderboard record.
# @param p_metadata - The metadata for the leaderboard record.
# Returns a task which resolves to the leaderboard record object written.
func write_leaderboard_record_async(p_session : NakamaSession,
p_leaderboard_id : String, p_score : int, p_subscore : int = 0, p_metadata = null): # -> NakamaAPI.ApiLeaderboardRecord:
return _api_client.write_leaderboard_record_async(p_session.token, p_leaderboard_id,
NakamaAPI.WriteLeaderboardRecordRequestLeaderboardRecordWrite.create(NakamaAPI, {
"metadata": p_metadata,
"score": str(p_score),
"subscore": str(p_subscore)
}))
# Write objects to the storage engine.
# @param p_session - The session of the user.
# @param p_objects - The objects to write.
# Returns a task which resolves to the storage write acknowledgements.
func write_storage_objects_async(p_session : NakamaSession, p_objects : Array): # -> NakamaAPI.ApiStorageObjectAcks:
var writes : Array = []
for obj in p_objects:
if not obj is NakamaWriteStorageObject:
continue # TODO Exceptions
var write_obj : NakamaWriteStorageObject = obj
writes.append(write_obj.as_write().serialize())
return _api_client.write_storage_objects_async(p_session.token,
NakamaAPI.ApiWriteStorageObjectsRequest.create(NakamaAPI, {
"objects": writes
}))
# Write a record to a tournament.
# @param p_session - The session of the user.
# @param p_tournament_id - The ID of the tournament to write.
# @param p_score - The score of the tournament record.
# @param p_subscore - The subscore for the tournament record.
# @param p_metadata - The metadata for the tournament record.
# Returns a task which resolves to the tournament record object written.
func write_tournament_record_async(p_session : NakamaSession,
p_tournament_id : String, p_score : int, p_subscore : int = 0, p_metadata = null): # -> NakamaAPI.ApiLeaderboardRecord:
return _api_client.write_tournament_record_async(p_session.token, p_tournament_id,
NakamaAPI.WriteTournamentRecordRequestTournamentRecordWrite.create(NakamaAPI, {
"metadata": p_metadata,
"score": str(p_score),
"subscore": str(p_subscore)
}))

View File

@ -0,0 +1,116 @@
tool
extends Node
# An adapter which implements the HTTP protocol.
class_name NakamaHTTPAdapter
# The logger to use with the adapter.
var logger : Reference = NakamaLogger.new()
var _pending = {}
var id : int = 0
# Send a HTTP request.
# @param method - HTTP method to use for this request.
# @param uri - The fully qualified URI to use.
# @param headers - Request headers to set.
# @param body - Request content body to set.
# @param timeoutSec - Request timeout.
# Returns a task which resolves to the contents of the response.
func send_async(p_method : String, p_uri : String, p_headers : Dictionary, p_body : PoolByteArray, p_timeout : int = 3):
var req = HTTPRequest.new()
if OS.get_name() != 'HTML5':
req.use_threads = true # Threads not available nor needed on the web.
# Parse method
var method = HTTPClient.METHOD_GET
if p_method == "POST":
method = HTTPClient.METHOD_POST
elif p_method == "PUT":
method = HTTPClient.METHOD_PUT
elif p_method == "DELETE":
method = HTTPClient.METHOD_DELETE
elif p_method == "HEAD":
method = HTTPClient.METHOD_HEAD
var headers = PoolStringArray()
# Parse headers
headers.append("Accept: application/json")
for k in p_headers:
headers.append("%s: %s" % [k, p_headers[k]])
# Handle timeout for 3.1 compatibility
id += 1
_pending[id] = [req, OS.get_ticks_msec() + (p_timeout * 1000)]
logger.debug("Sending request [ID: %d, Method: %s, Uri: %s, Headers: %s, Body: %s, Timeout: %d]" % [
id, p_method, p_uri, p_headers, p_body.get_string_from_utf8(), p_timeout
])
add_child(req)
return _send_async(req, p_uri, headers, method, p_body, id, _pending, logger)
func _process(delta):
# Handle timeout for 3.1 compatibility
var ids = _pending.keys()
for id in ids:
var p = _pending[id]
if p[0].is_queued_for_deletion():
_pending.erase(id)
continue
if p[1] < OS.get_ticks_msec():
logger.debug("Request %d timed out" % id)
p[0].cancel_request()
_pending.erase(id)
p[0].emit_signal("request_completed", HTTPRequest.RESULT_REQUEST_FAILED, 0, PoolStringArray(), PoolByteArray())
static func _send_async(request : HTTPRequest, p_uri : String, p_headers : PoolStringArray,
p_method : int, p_body : PoolByteArray, p_id : int, p_pending : Dictionary, logger : NakamaLogger):
var err = request.request(p_uri, p_headers, true, p_method, p_body.get_string_from_utf8())
if err != OK:
yield(request.get_tree(), "idle_frame")
logger.debug("Request %d failed to start, error: %d" % [p_id, err])
request.queue_free()
return NakamaException.new("Request failed")
var args = yield(request, "request_completed")
var result = args[0]
var response_code = args[1]
var _headers = args[2]
var body = args[3]
# Will be deleted next frame
if not request.is_queued_for_deletion():
request.queue_free()
p_pending.erase(p_id)
if result != HTTPRequest.RESULT_SUCCESS:
logger.debug("Request %d failed with result: %d, response code: %d" % [
p_id, result, response_code
])
return NakamaException.new("HTTPRequest failed!", result)
var json : JSONParseResult = JSON.parse(body.get_string_from_utf8())
if json.error != OK:
logger.debug("Unable to parse request %d response. JSON error: %d, response code: %d" % [
p_id, json.error, response_code
])
return NakamaException.new("Failed to decode JSON response", response_code)
if response_code != HTTPClient.RESPONSE_OK:
var error = ""
var code = -1
if typeof(json.result) == TYPE_DICTIONARY:
error = json.result["error"] if "error" in json.result else str(json.result)
code = json.result["code"] if "code" in json.result else -1
else:
error = str(json.result)
if typeof(error) == TYPE_DICTIONARY:
error = JSON.print(error)
logger.debug("Request %d returned response code: %d, RPC code: %d, error: %s" % [
p_id, response_code, code, error
])
return NakamaException.new(error, response_code, code)
return json.result

View File

@ -0,0 +1,433 @@
extends Reference
# A socket to interact with Nakama server.
class_name NakamaSocket
const ChannelType = NakamaRTMessage.ChannelJoin.ChannelType
# Emitted when a socket is closed.
signal closed()
# Emitted when a socket is connected.
signal connected()
# Emitted when a chat channel message is received
signal received_channel_message(p_channel_message) # ApiChannelMessage
# Emitted when receiving a presence change for joins and leaves with users in a chat channel.
signal received_channel_presence(p_channel_presence) # ChannelPresenceEvent
# Emitted when an error occurs on the socket.
signal received_error(p_error)
# Emitted when receiving a matchmaker matched message.
signal received_matchmaker_matched(p_matchmaker_matched) # MatchmakerMatched
# Emitted when receiving a message from a multiplayer match.
signal received_match_state(p_match_state) # MatchData
# Emitted when receiving a presence change for joins and leaves of users in a multiplayer match.
signal received_match_presence(p_match_presence_event) # MatchPresenceEvent
# Emitted when receiving a notification for the current user.
signal received_notification(p_api_notification) # ApiNotification
# Emitted when receiving a presence change for when a user updated their online status.
signal received_status_presence(p_status_presence_event) # StatusPresenceEvent
# Emitted when receiving a presence change for joins and leaves on a realtime stream.
signal received_stream_presence(p_stream_presence_event) # StreamPresenceEvent
# Emitted when receiving a message from a realtime stream.
signal received_stream_state(p_stream_state) # StreamState
var _adapter : NakamaSocketAdapter
var _free_adapter : bool = false
var _weak_ref : WeakRef
var _base_uri : String
var _responses : Dictionary
var _last_id : int = 1
var _conn : GDScriptFunctionState = null
var logger : NakamaLogger = null
func _resume_conn(p_err : int):
if _conn:
if p_err: # Exception
logger.warning("Connection error: %d" % p_err)
_conn.resume(NakamaAsyncResult.new(NakamaException.new()))
else:
logger.info("Connected!")
_conn.resume(NakamaAsyncResult.new())
call_deferred("_survive", _conn)
_conn = null
func _init(p_adapter : NakamaSocketAdapter,
p_host : String,
p_port : int,
p_scheme : String,
p_free_adapter : bool = false):
logger = p_adapter.logger
_adapter = p_adapter
_weak_ref = weakref(_adapter)
var port = ""
if (p_scheme == "ws" and p_port != 80) or (p_scheme == "wss" and p_port != 443):
port = ":%d" % p_port
_base_uri = "%s://%s%s" % [p_scheme, p_host, port]
_free_adapter = p_free_adapter
_adapter.connect("closed", self, "_closed")
_adapter.connect("connected", self, "_connected")
_adapter.connect("received_error", self, "_error")
_adapter.connect("received", self, "_received")
func _notification(what):
if what == NOTIFICATION_PREDELETE:
# Is this a bug? Why can't I call a function? self is null...
# _clear_responses()
# _resume_conn(ERR_FILE_EOF)
var keys = _responses.keys()
for k in keys:
_responses[k].resume(NakamaException.new("Cancelled!"))
if _conn != null:
_conn.resume(ERR_FILE_EOF)
call_deferred("_survive", _conn)
_conn = null
if _weak_ref.get_ref() == null:
return
_adapter.close()
if _free_adapter:
_adapter.queue_free()
func _closed(p_error = null):
emit_signal("closed")
_resume_conn(ERR_CANT_CONNECT)
_clear_responses()
func _error(p_error):
emit_signal("received_error", p_error)
_resume_conn(p_error)
_clear_responses()
func _connected():
emit_signal("connected")
_resume_conn(OK)
func _received(p_bytes : PoolByteArray):
var json_str = p_bytes.get_string_from_utf8()
var json := JSON.parse(json_str)
if json.error != OK or typeof(json.result) != TYPE_DICTIONARY:
logger.error("Unable to parse response: %s" % json_str)
return
var dict : Dictionary = json.result
var cid = dict.get("cid")
if cid:
if _responses.has(cid):
_resume_response(cid, dict)
else:
logger.error("Invalid call id received %s" % dict)
else:
if dict.has("channel_message"):
var res = NakamaAPI.ApiChannelMessage.create(NakamaAPI, dict["channel_message"])
emit_signal("received_channel_message", res)
elif dict.has("channel_presence_event"):
var res = NakamaRTAPI.ChannelPresenceEvent.create(NakamaRTAPI, dict["channel_presence_event"])
emit_signal("received_channel_presence", res)
elif dict.has("match_data"):
var res = NakamaRTAPI.MatchData.create(NakamaRTAPI, dict["match_data"])
emit_signal("received_match_state", res)
elif dict.has("match_presence_event"):
var res = NakamaRTAPI.MatchPresenceEvent.create(NakamaRTAPI, dict["match_presence_event"])
emit_signal("received_match_presence", res)
elif dict.has("matchmaker_matched"):
var res = NakamaRTAPI.MatchmakerMatched.create(NakamaRTAPI, dict["matchmaker_matched"])
emit_signal("received_matchmaker_matched", res)
elif dict.has("notifications"):
var res = NakamaAPI.ApiNotificationList.create(NakamaAPI, dict["notifications"])
for n in res.notifications:
emit_signal("received_notification", n)
elif dict.has("status_presence_event"):
var res = NakamaRTAPI.StatusPresenceEvent.create(NakamaRTAPI, dict["status_presence_event"])
emit_signal("received_status_presence", res)
elif dict.has("stream_presence_event"):
var res = NakamaRTAPI.StreamPresenceEvent.create(NakamaRTAPI, dict["stream_presence_event"])
emit_signal("received_stream_presence", res)
elif dict.has("stream_data"):
var res = NakamaRTAPI.StreamData.create(NakamaRTAPI, dict["stream_data"])
emit_signal("received_stream_state", res)
else:
logger.warning("Unhandled response: %s" % dict)
func _resume_response(p_id : String, p_data):
if _responses.has(p_id):
logger.debug("Resuming response: %s: %s" % [p_id, p_data])
_responses[p_id].resume(p_data)
else:
logger.warning("Trying to resume missing response: %s: %s" % [p_id, p_data])
func _cancel_response(p_id : String):
logger.debug("Cancelling response: %s" % [p_id])
_resume_response(p_id, NakamaException.new("Request cancelled."))
func _clear_responses():
var ids = _responses.keys()
for id in ids:
_cancel_response(id)
func _survive(p_ref):
pass
func _parse_result(p_responses : Dictionary, p_id : String, p_type, p_ns : GDScript, p_result_key = null):
# Specifically defined key, or default for objject
var result_key = p_result_key
if p_type != NakamaAsyncResult and result_key == null:
result_key = p_type.get_result_key()
# Here we yield and wait
var data = yield() # Manually resumed
call_deferred("_survive", p_responses[p_id])
p_responses.erase(p_id) # Remove this request from the list of responses
# We got an exception, maybe the task was cancelled?
if data is NakamaException:
return p_type.new(data as NakamaException)
# Error from server
if data.has("error"):
var err = data["error"]
var code = -1
var msg = str(err)
if typeof(err) == TYPE_DICTIONARY:
msg = err.get("message", "")
code = err.get("code", -1)
logger.warning("Error response from server: %s" % err)
return p_type.new(NakamaException.new(msg, code))
# Simple ack response
elif p_type == NakamaAsyncResult:
return NakamaAsyncResult.new()
# Missing expected result key
elif not data.has(result_key):
logger.warning("Missing expected result key: %s" % result_key)
return p_type.new(NakamaException.new("Missing expected result key: %s" % result_key))
# All good, proceed with parsing
else:
return p_type.create(p_ns, data.get(result_key))
func _send_async(p_message, p_parse_type = NakamaAsyncResult, p_ns = NakamaRTAPI, p_msg_key = null, p_result_key = null):
logger.debug("Sending async request: %s" % p_message)
# For messages coming from the API which does not have a key defined, so we can override it
var msg = p_msg_key
# For regular RT messages
if msg == null:
msg = p_message.get_msg_key()
var id = str(_last_id)
_last_id += 1
_responses[id] = _parse_result(_responses, id, p_parse_type, p_ns, p_result_key)
var json := JSON.print({
"cid": id,
msg: p_message.serialize()
})
var err = _adapter.send(json.to_utf8())
if err != OK:
call_deferred("_cancel_response", id)
return _responses[id]
func _connect_function():
return yield() # Manually resumed
# If the socket is connected.
func is_connected_to_host():
return _adapter.is_connected_to_host()
# If the socket is connecting.
func is_connecting_to_host():
return _adapter.is_connecting_to_host()
# Close the socket connection to the server.
func close():
_adapter.close()
# Connect to the server.
# @param p_session - The session of the user.
# @param p_appear_online - If the user who appear online to other users.
# @param p_connect_timeout - The time allowed for the socket connection to be established.
# Returns a task to represent the asynchronous operation.
func connect_async(p_session : NakamaSession, p_appear_online : bool = false, p_connect_timeout : int = 3):
var uri = "%s/ws?lang=en&status=%s&token=%s" % [_base_uri, str(p_appear_online).to_lower(), p_session.token]
logger.debug("Connecting to host: %s" % uri)
_adapter.connect_to_host(uri, p_connect_timeout)
_conn = _connect_function()
return _conn
# Join the matchmaker pool and search for opponents on the server.
# @param p_query - The matchmaker query to search for opponents.
# @param p_min_count - The minimum number of players to compete against in a match.
# @param p_max_count - The maximum number of players to compete against in a match.
# @param p_string_properties - A set of key/value properties to provide to searches.
# @param p_numeric_properties - A set of key/value numeric properties to provide to searches.
# Returns a task which resolves to a matchmaker ticket object.
func add_matchmaker_async(p_query : String = "*", p_min_count : int = 2, p_max_count : int = 8,
p_string_props : Dictionary = {}, p_numeric_props : Dictionary = {}) -> NakamaRTAPI.MatchmakerTicket:
return _send_async(
NakamaRTMessage.MatchmakerAdd.new(p_query, p_min_count, p_max_count, p_string_props, p_numeric_props),
NakamaRTAPI.MatchmakerTicket
)
## <summary>
## Create a multiplayer match on the server.
## </summary>
## Returns a task to represent the asynchronous operation.
func create_match_async():
return _send_async(NakamaRTMessage.MatchCreate.new(), NakamaRTAPI.Match)
# Subscribe to one or more users for their status updates.
# @param p_user_ids - The IDs of users.
# @param p_usernames - The usernames of the users.
# Returns a task which resolves to the current statuses for the users.
func follow_users_async(p_ids : PoolStringArray, p_usernames : PoolStringArray = []) -> NakamaRTAPI.Status:
return _send_async(NakamaRTMessage.StatusFollow.new(p_ids, p_usernames), NakamaRTAPI.Status)
# Join a chat channel on the server.
# @param p_target - The target channel to join.
# @param p_type - The type of channel to join.
# @param p_persistence - If chat messages should be stored.
# @param p_hidden - If the current user should be hidden on the channel.
# Returns a task which resolves to a chat channel object.
func join_chat_async(p_target : String, p_type : int, p_persistence : bool = false, p_hidden : bool = false) -> NakamaRTAPI.Channel:
return _send_async(
NakamaRTMessage.ChannelJoin.new(p_target, p_type, p_persistence, p_hidden),
NakamaRTAPI.Channel
)
# Join a multiplayer match with the matchmaker matched object.
# @param p_matched - A matchmaker matched object.
# Returns a task which resolves to a multiplayer match.
func join_matched_async(p_matched):
var msg := NakamaRTMessage.MatchJoin.new()
if p_matched.match_id:
msg.match_id = p_matched.match_id
else:
msg.token = p_matched.token
return _send_async(msg, NakamaRTAPI.Match)
# Join a multiplayer match by ID.
# @param p_match_id - The ID of the match to attempt to join.
# @param p_metadata - An optional set of key-value metadata pairs to be passed to the match handler.
# Returns a task which resolves to a multiplayer match.
func join_match_async(p_match_id : String, p_metadata = null):
var msg := NakamaRTMessage.MatchJoin.new()
msg.match_id = p_match_id
return _send_async(msg, NakamaRTAPI.Match)
# Leave a chat channel on the server.
## @param p_channel_id - The ID of the chat channel to leave.
# Returns a task which represents the asynchronous operation.
func leave_chat_async(p_channel_id : String) -> NakamaAsyncResult:
return _send_async(NakamaRTMessage.ChannelLeave.new(p_channel_id))
# Leave a multiplayer match on the server.
# @param p_match_id - The multiplayer match to leave.
# Returns a task which represents the asynchronous operation.
func leave_match_async(p_match_id : String) -> NakamaAsyncResult:
return _send_async(NakamaRTMessage.MatchLeave.new(p_match_id))
# Remove a chat message from a chat channel on the server.
# @param p_channel - The chat channel with the message to remove.
# @param p_message_id - The ID of the chat message to remove.
# Returns a task which resolves to an acknowledgement of the removed message.
func remove_chat_message_async(p_channel_id : String, p_message_id : String):
return _send_async(
NakamaRTMessage.ChannelMessageRemove.new(p_channel_id, p_message_id),
NakamaRTAPI.ChannelMessageAck
)
# Leave the matchmaker pool with the ticket.
# @param p_ticket - The ticket returned by the matchmaker on join.
# Returns a task which represents the asynchronous operation.
func remove_matchmaker_async(p_ticket : String) -> NakamaAsyncResult:
return _send_async(NakamaRTMessage.MatchmakerRemove.new(p_ticket))
# Execute an RPC function to the server.
# @param p_func_id - The ID of the function to execute.
# @param p_payload - An (optional) String payload to send to the server.
# Returns a task which resolves to the RPC function response object.
func rpc_async(p_func_id : String, p_payload = null) -> NakamaAPI.ApiRpc:
var payload = p_payload
match typeof(p_payload):
TYPE_NIL, TYPE_STRING:
pass
_:
payload = JSON.print(p_payload)
return _send_async(NakamaAPI.ApiRpc.create(NakamaAPI, {
"id": p_func_id,
"payload": payload
}), NakamaAPI.ApiRpc, NakamaAPI, "rpc", "rpc")
# Send input to a multiplayer match on the server.
# When no presences are supplied the new match state will be sent to all presences.
# @param p_match_id - The ID of the match.
# @param p_op_code - An operation code for the input.
# @param p_data - The input data to send.
# @param p_presences - The presences in the match who should receive the input.
# Returns a task which represents the asynchronous operation.
func send_match_state_async(p_match_id, p_op_code : int, p_data : String, p_presences = null):
var req = _send_async(NakamaRTMessage.MatchDataSend.new(
p_match_id,
p_op_code,
Marshalls.utf8_to_base64(p_data),
p_presences
))
# This do not return a response from server, you don't really need to wait for it.
req.call_deferred("resume", {})
call_deferred("_survive", req)
return req
# Send input to a multiplayer match on the server.
# When no presences are supplied the new match state will be sent to all presences.
# @param p_match_id - The ID of the match.
# @param p_op_code - An operation code for the input.
# @param p_data - The input data to send.
# @param p_presences - The presences in the match who should receive the input.
# Returns a task which represents the asynchronous operation.
func send_match_state_raw_async(p_match_id, p_op_code : int, p_data : PoolByteArray, p_presences = null):
var req = _send_async(NakamaRTMessage.MatchDataSend.new(
p_match_id,
p_op_code,
Marshalls.raw_to_base64(p_data),
p_presences
))
# This do not return a response from server, you don't really need to wait for it.
req.call_deferred("resume", {})
call_deferred("_survive", req)
return req
# Unfollow one or more users from their status updates.
# @param p_user_ids - An array of user ids to unfollow.
# Returns a task which represents the asynchronous operation.
func unfollow_users_async(p_ids : PoolStringArray):
return _send_async(NakamaRTMessage.StatusUnfollow.new(p_ids))
# Update a chat message on a chat channel in the server.
# @param p_channel_id - The ID of the chat channel with the message to update.
# @param p_message_id - The ID of the message to update.
# @param p_content - The new contents of the chat message.
# Returns a task which resolves to an acknowledgement of the updated message.
func update_chat_message_async(p_channel_id : String, p_message_id : String, p_content : Dictionary):
return _send_async(
NakamaRTMessage.ChannelMessageUpdate.new(p_channel_id, p_message_id, JSON.print(p_content)),
NakamaRTAPI.ChannelMessageAck
)
# Update the status for the current user online.
# @param p_status - The new status for the user.
# Returns a task which represents the asynchronous operation.
func update_status_async(p_status : String):
return _send_async(NakamaRTMessage.StatusUpdate.new(p_status))
# Send a chat message to a chat channel on the server.
# @param p_channel_id - The ID of the chat channel to send onto.
# @param p_content - The contents of the message to send.
# Returns a task which resolves to the acknowledgement of the chat message write.
func write_chat_message_async(p_channel_id : String, p_content : Dictionary):
return _send_async(
NakamaRTMessage.ChannelMessageSend.new(p_channel_id, JSON.print(p_content)),
NakamaRTAPI.ChannelMessageAck
)

View File

@ -0,0 +1,82 @@
tool
extends Node
# An adapter which implements a socket with a protocol supported by Nakama.
class_name NakamaSocketAdapter
var _ws := WebSocketClient.new()
var _timeout : int = 30
var _start : int = 0
var logger = NakamaLogger.new()
# A signal emitted when the socket is connected.
signal connected()
# A signal emitted when the socket is disconnected.
signal closed()
# A signal emitted when the socket has an error when connected.
signal received_error(p_exception)
# A signal emitted when the socket receives a message.
signal received(p_bytes) # PoolByteArray
# If the socket is connected.
func is_connected_to_host():
return _ws.get_connection_status() == WebSocketClient.CONNECTION_CONNECTED
# If the socket is connecting.
func is_connecting_to_host():
return _ws.get_connection_status() == WebSocketClient.CONNECTION_CONNECTING
# Close the socket with an asynchronous operation.
func close():
_ws.disconnect_from_host()
# Connect to the server with an asynchronous operation.
# @param p_uri - The URI of the server.
# @param p_timeout - The timeout for the connect attempt on the socket.
func connect_to_host(p_uri : String, p_timeout : int):
_ws.disconnect_from_host()
_timeout = p_timeout
_start = OS.get_unix_time()
var err = _ws.connect_to_url(p_uri)
if err != OK:
logger.debug("Error connecting to host %s" % p_uri)
call_deferred("emit_signal", "received_error", err)
# Send data to the server with an asynchronous operation.
# @param p_buffer - The buffer with the message to send.
# @param p_reliable - If the message should be sent reliably (will be ignored by some protocols).
func send(p_buffer : PoolByteArray, p_reliable : bool = true) -> int:
return _ws.get_peer(1).put_packet(p_buffer)
func _process(delta):
if _ws.get_connection_status() == WebSocketClient.CONNECTION_CONNECTING:
if _start + _timeout < OS.get_unix_time():
logger.debug("Timeout when connecting to socket")
emit_signal("received_error", ERR_TIMEOUT)
_ws.disconnect_from_host()
else:
_ws.poll()
if _ws.get_connection_status() != WebSocketClient.CONNECTION_DISCONNECTED:
_ws.poll()
func _init():
_ws.connect("data_received", self, "_received")
_ws.connect("connection_established", self, "_connected")
_ws.connect("connection_error", self, "_error")
_ws.connect("connection_closed", self, "_closed")
func _received():
emit_signal("received", _ws.get_peer(1).get_packet())
func _connected(p_protocol : String):
_ws.get_peer(1).set_write_mode(WebSocketPeer.WRITE_MODE_TEXT)
emit_signal("connected")
func _error():
emit_signal("received_error", FAILED)
func _closed(p_clean : bool):
emit_signal("closed")

View File

@ -0,0 +1,29 @@
extends Reference
class_name NakamaAsyncResult
var exception : NakamaException setget _no_set, get_exception
var _ex = null
func _no_set(v):
return
func _init(p_ex = null):
_ex = p_ex
func is_exception():
return get_exception() != null
func get_exception() -> NakamaException:
return _ex as NakamaException
func _to_string():
if is_exception():
return get_exception()._to_string()
return "NakamaAsyncResult<>"
static func _safe_ret(p_obj, p_type : GDScript):
if p_obj is p_type:
return p_obj # Correct type
elif p_obj is NakamaException:
return p_type.new(p_obj) # It's an exception. Incapsulate it
return p_type.new(NakamaException.new()) # It's something else. generate an exception

View File

@ -0,0 +1,20 @@
extends Reference
# An exception generated during a request.
# Usually contains at least an error message.
class_name NakamaException
var status_code : int = -1 setget _no_set
var grpc_status_code : int = -1 setget _no_set
var message : String = "" setget _no_set
func _no_set(_p):
pass
func _init(p_message : String = "", p_status_code : int = -1, p_grpc_status_code : int = -1):
status_code = p_status_code
grpc_status_code = p_grpc_status_code
message = p_message
func _to_string() -> String:
return "NakamaException(StatusCode={%s}, Message='{%s}', GrpcStatusCode={%s})" % [status_code, message, grpc_status_code]

View File

@ -0,0 +1,38 @@
extends Reference
class_name NakamaLogger
enum LOG_LEVEL {NONE, ERROR, WARNING, INFO, VERBOSE, DEBUG}
var _level = LOG_LEVEL.ERROR
var _module = "Nakama"
func _init(p_module : String = "Nakama", p_level : int = LOG_LEVEL.ERROR):
_level = p_level
_module = p_module
func _log(level : int, msg):
if level <= _level:
if level == LOG_LEVEL.ERROR:
printerr("=== %s : ERROR === %s" % [_module, str(msg)])
else:
var what = "=== UNKNOWN === "
for k in LOG_LEVEL:
if level == LOG_LEVEL[k]:
what = "=== %s : %s === " % [_module, k]
break
print(what + str(msg))
func error(msg):
_log(LOG_LEVEL.ERROR, msg)
func warning(msg):
_log(LOG_LEVEL.WARNING, msg)
func info(msg):
_log(LOG_LEVEL.INFO, msg)
func verbose(msg):
_log(LOG_LEVEL.VERBOSE, msg)
func debug(msg):
_log(LOG_LEVEL.DEBUG, msg)

View File

@ -0,0 +1,145 @@
extends Reference
class_name NakamaSerializer
static func serialize(p_obj : Object) -> Dictionary:
var out = {}
var schema = p_obj.get("_SCHEMA")
if schema == null:
return {} # No schema defined
for k in schema:
var prop = schema[k]
var val = p_obj.get(prop["name"])
if val == null:
continue
var type = prop["type"]
var content = prop.get("content", TYPE_NIL)
if typeof(content) == TYPE_STRING:
content = TYPE_OBJECT
var val_type = typeof(val)
match val_type:
TYPE_OBJECT: # Simple objects
out[k] = serialize(val)
TYPE_ARRAY: # Array of objects
var arr = []
for e in val:
if typeof(e) != TYPE_OBJECT:
continue
arr.append(serialize(e))
out[k] = arr
TYPE_INT_ARRAY, TYPE_STRING_ARRAY: # Array of ints, bools, or strings
var arr = []
for e in val:
if content == TYPE_BOOL:
e = bool(e)
if typeof(e) != content:
continue
arr.append(e)
out[k] = arr
TYPE_DICTIONARY: # Maps
var dict = {}
if content == TYPE_OBJECT: # Map of objects
for l in val:
if val_type != TYPE_OBJECT:
continue
dict[l] = serialize(val)
else: # Map of simple types
for l in val:
if val_type != content:
continue
dict[l] = val
_:
out[k] = val
return out
static func deserialize(p_ns : GDScript, p_cls_name : String, p_dict : Dictionary) -> Object:
var cls : GDScript = p_ns.get(p_cls_name)
var schema = cls.get("_SCHEMA")
if schema == null:
return NakamaException.new() # No schema defined
var obj = cls.new()
for k in schema:
var prop = schema[k]
var pname = prop["name"]
var type = prop["type"]
var required = prop["required"]
var content = prop.get("content", TYPE_NIL)
var type_cmp = type
if typeof(type) == TYPE_STRING: # A class
type_cmp = TYPE_DICTIONARY
if type_cmp == TYPE_STRING_ARRAY or type_cmp == TYPE_INT_ARRAY: # A specialized array
type_cmp = TYPE_ARRAY
var content_cmp = content
if typeof(content) == TYPE_STRING: # A dictionary or array of classes
content_cmp = TYPE_DICTIONARY
var val = p_dict.get(k, null)
# Ints might and up being recognized as floats. Change that if needed
if typeof(val) == TYPE_REAL and type_cmp == TYPE_INT:
val = int(val)
if typeof(val) == type_cmp:
if typeof(type) == TYPE_STRING:
obj.set(pname, deserialize(p_ns, type, val))
elif type_cmp == TYPE_DICTIONARY:
var v = {}
for l in val:
if typeof(content) == TYPE_STRING:
v[l] = deserialize(p_ns, content, val[l])
elif content == TYPE_INT:
v[l] = int(val[l])
elif content == TYPE_BOOL:
v[l] = bool(val[l])
else:
v[l] = str(val[l])
obj.set(pname, v)
elif type_cmp == TYPE_ARRAY:
var v
match content:
TYPE_INT, TYPE_BOOL: v = PoolIntArray()
TYPE_STRING: v = PoolStringArray()
_: v = Array()
for e in val:
if typeof(content) == TYPE_STRING:
v.append(deserialize(p_ns, content, e))
elif content == TYPE_INT:
v.append(int(e))
elif content == TYPE_BOOL:
v.append(bool(e))
else:
v.append(str(e))
obj.set(pname, v)
else:
obj.set(pname, val)
elif required:
obj._ex = NakamaException.new("ERROR [%s]: Missing or invalid required prop %s = %s:\n\t%s" % [p_cls_name, prop, p_dict.get(k), p_dict])
return obj
return obj
###
# Compatibility with Godot 3.1 which does not expose String.http_escape
###
const HEX = ["0","1","2","3","4","5","6","7","8","9","A","B","C","D","E","F"]
static func escape_http(p_str : String) -> String:
var out : String = ""
for o in p_str:
if (o == '.' or o == '-' or o == '_' or o == '~' or
(o >= 'a' and o <= 'z') or
(o >= 'A' and o <= 'Z') or
(o >= '0' and o <= '9')):
out += o
else:
for b in o.to_utf8():
out += "%%%s" % to_hex(b)
return out
static func to_hex(p_val : int) -> String:
var v := p_val
var o := ""
while v != 0:
o = HEX[v % 16] + o
v /= 16
return o

View File

@ -8,17 +8,105 @@
config_version=4
_global_script_classes=[ ]
_global_script_classes=[ {
"base": "Reference",
"class": "NakamaAPI",
"language": "GDScript",
"path": "res://addons/com.heroiclabs.nakama/api/NakamaAPI.gd"
}, {
"base": "Reference",
"class": "NakamaAsyncResult",
"language": "GDScript",
"path": "res://addons/com.heroiclabs.nakama/utils/NakamaAsyncResult.gd"
}, {
"base": "Reference",
"class": "NakamaClient",
"language": "GDScript",
"path": "res://addons/com.heroiclabs.nakama/client/NakamaClient.gd"
}, {
"base": "Reference",
"class": "NakamaException",
"language": "GDScript",
"path": "res://addons/com.heroiclabs.nakama/utils/NakamaException.gd"
}, {
"base": "Node",
"class": "NakamaHTTPAdapter",
"language": "GDScript",
"path": "res://addons/com.heroiclabs.nakama/client/NakamaHTTPAdapter.gd"
}, {
"base": "Reference",
"class": "NakamaLogger",
"language": "GDScript",
"path": "res://addons/com.heroiclabs.nakama/utils/NakamaLogger.gd"
}, {
"base": "NakamaAsyncResult",
"class": "NakamaRTAPI",
"language": "GDScript",
"path": "res://addons/com.heroiclabs.nakama/api/NakamaRTAPI.gd"
}, {
"base": "Reference",
"class": "NakamaRTMessage",
"language": "GDScript",
"path": "res://addons/com.heroiclabs.nakama/api/NakamaRTMessage.gd"
}, {
"base": "Reference",
"class": "NakamaSerializer",
"language": "GDScript",
"path": "res://addons/com.heroiclabs.nakama/utils/NakamaSerializer.gd"
}, {
"base": "NakamaAsyncResult",
"class": "NakamaSession",
"language": "GDScript",
"path": "res://addons/com.heroiclabs.nakama/api/NakamaSession.gd"
}, {
"base": "Reference",
"class": "NakamaSocket",
"language": "GDScript",
"path": "res://addons/com.heroiclabs.nakama/socket/NakamaSocket.gd"
}, {
"base": "Node",
"class": "NakamaSocketAdapter",
"language": "GDScript",
"path": "res://addons/com.heroiclabs.nakama/socket/NakamaSocketAdapter.gd"
}, {
"base": "Reference",
"class": "NakamaStorageObjectId",
"language": "GDScript",
"path": "res://addons/com.heroiclabs.nakama/api/NakamaStorageObjectId.gd"
}, {
"base": "Reference",
"class": "NakamaWriteStorageObject",
"language": "GDScript",
"path": "res://addons/com.heroiclabs.nakama/api/NakamaWriteStorageObject.gd"
} ]
_global_script_class_icons={
"NakamaAPI": "",
"NakamaAsyncResult": "",
"NakamaClient": "",
"NakamaException": "",
"NakamaHTTPAdapter": "",
"NakamaLogger": "",
"NakamaRTAPI": "",
"NakamaRTMessage": "",
"NakamaSerializer": "",
"NakamaSession": "",
"NakamaSocket": "",
"NakamaSocketAdapter": "",
"NakamaStorageObjectId": "",
"NakamaWriteStorageObject": ""
}
[application]
config/name="Family"
run/main_scene="res://default.tscn"
run/main_scene="res://scenes/AuthScene.tscn"
config/icon="res://icon.png"
[autoload]
Nakama="*res://addons/com.heroiclabs.nakama/Nakama.gd"
ServerConnection="*res://scripts/singletons/ServerConnection.gd"
[rendering]
quality/driver/driver_name="GLES2"

View File

@ -0,0 +1,22 @@
extends Node
# Declare member variables here. Examples:
# var a = 2
# var b = "text"
# Called when the node enters the scene tree for the first time.
func _ready():
return
var result : int
result = yield(ServerConnection.authenticate_async("j@cloudsumu.com", "Learning12!"), "completed")
if result == null:
print("Logged In")
else:
print("Auth failed! Error code: %d" % result)
result = yield(ServerConnection.signup_async("j@cloudsumu.com", "Learing12!"), "completed")
if result == null:
print("Registered!")
else:
print("Signup failed! Error code: %d" % result)

View File

@ -0,0 +1,153 @@
[gd_scene load_steps=3 format=2]
[ext_resource path="res://scenes/AuthScene.gd" type="Script" id=1]
[ext_resource path="res://scripts/menus/signup_form.gd" type="Script" id=2]
[node name="AuthScene" type="Control"]
anchor_right = 1.0
anchor_bottom = 1.0
script = ExtResource( 1 )
__meta__ = {
"_edit_use_anchors_": false
}
[node name="SignupDialog" type="WindowDialog" parent="."]
anchor_left = 0.5
anchor_top = 0.5
anchor_right = 0.5
anchor_bottom = 0.5
margin_left = -256.0
margin_top = -140.0
margin_right = 256.0
margin_bottom = 140.0
window_title = "Registration"
script = ExtResource( 2 )
__meta__ = {
"_edit_use_anchors_": false
}
usernamePath = NodePath("UsernameEdit")
passwordPath = NodePath("PasswordEdit")
confirmPasswordPath = NodePath("CPasswordEdit")
buttonPath = NodePath("SignupButton")
errorPath = NodePath("ErrorLabel")
[node name="MessageLabel" type="Label" parent="SignupDialog"]
anchor_left = 0.5
anchor_right = 0.5
margin_left = -208.0
margin_top = 16.0
margin_right = 208.0
margin_bottom = 46.0
text = "Welcome to the family!"
align = 1
valign = 1
__meta__ = {
"_edit_use_anchors_": false
}
[node name="ErrorLabel" type="Label" parent="SignupDialog"]
anchor_left = 0.5
anchor_right = 0.5
margin_left = -232.0
margin_top = 48.0
margin_right = 228.0
margin_bottom = 62.0
custom_colors/font_color = Color( 1, 0, 0, 1 )
text = "[Errors go here]"
align = 1
__meta__ = {
"_edit_use_anchors_": false
}
[node name="UsernameLabel" type="Label" parent="SignupDialog"]
anchor_left = 0.5
anchor_right = 0.5
margin_left = -232.0
margin_top = 72.0
margin_right = -193.0
margin_bottom = 86.0
text = "Email:"
__meta__ = {
"_edit_use_anchors_": false
}
[node name="UsernameEdit" type="LineEdit" parent="SignupDialog"]
anchor_left = 0.5
anchor_right = 0.5
margin_left = -232.0
margin_top = 88.0
margin_right = 232.0
margin_bottom = 112.0
[node name="PasswordLabel" type="Label" parent="SignupDialog"]
anchor_left = 0.5
anchor_right = 0.5
margin_left = -232.0
margin_top = 128.0
margin_right = -168.0
margin_bottom = 142.0
text = "Password:"
__meta__ = {
"_edit_use_anchors_": false
}
[node name="PasswordEdit" type="LineEdit" parent="SignupDialog"]
anchor_left = 0.5
anchor_right = 0.5
margin_left = -232.0
margin_top = 144.0
margin_right = 232.0
margin_bottom = 168.0
secret = true
__meta__ = {
"_edit_use_anchors_": false
}
[node name="CPasswordLabel" type="Label" parent="SignupDialog"]
anchor_left = 0.5
anchor_right = 0.5
margin_left = -232.0
margin_top = 176.0
margin_right = -168.0
margin_bottom = 190.0
text = "Confirm Password:"
__meta__ = {
"_edit_use_anchors_": false
}
[node name="CPasswordEdit" type="LineEdit" parent="SignupDialog"]
anchor_left = 0.5
anchor_right = 0.5
margin_left = -232.0
margin_top = 192.0
margin_right = 232.0
margin_bottom = 216.0
secret = true
__meta__ = {
"_edit_use_anchors_": false
}
[node name="SignupButton" type="Button" parent="SignupDialog"]
anchor_left = 0.5
anchor_top = 1.0
anchor_right = 0.5
anchor_bottom = 1.0
margin_left = 136.0
margin_top = -44.0
margin_right = 228.0
margin_bottom = -16.0
disabled = true
text = "Sign Up!"
__meta__ = {
"_edit_use_anchors_": false
}
[node name="Button" type="Button" parent="."]
anchor_left = 1.0
anchor_top = 1.0
anchor_right = 1.0
anchor_bottom = 1.0
margin_left = -109.0
margin_top = -20.0
text = "Create Account"
[connection signal="button_down" from="Button" to="SignupDialog" method="popup_centered"]

View File

@ -0,0 +1,64 @@
extends Popup
export(NodePath) var usernamePath
export(NodePath) var passwordPath
export(NodePath) var confirmPasswordPath
export(NodePath) var buttonPath
export(NodePath) var errorPath
var usernameEdit : LineEdit
var passwordEdit : LineEdit
var cPasswordEdit : LineEdit
var errorLabel : Label
var button : Button
const MIN_PASSWORD_LENGTH = 8
func _ready():
# Get nodes
usernameEdit = get_node(usernamePath)
passwordEdit = get_node(passwordPath)
cPasswordEdit = get_node(confirmPasswordPath)
errorLabel = get_node(errorPath)
button = get_node(buttonPath)
# Set forms to validate on value chagne
usernameEdit.connect("text_changed", self, "validate_fields")
passwordEdit.connect("text_changed", self, "validate_fields")
cPasswordEdit.connect("text_changed", self, "validate_fields")
# Connect submission button
button.connect("button_down", self, "signup")
# Clear error message
errorLabel.text = ""
func signup():
var error : NakamaException = yield(ServerConnection.signup_async(usernameEdit.text, passwordEdit.text), "completed")
# Check for error
if error:
errorLabel.text = error.message
else:
print("Signed up successfully!")
# Close signup form
hide()
func validate_fields(_text=""):
var valid : bool = check_email(usernameEdit.text) and passwords_valid(passwordEdit.text, cPasswordEdit.text)
button.disabled = !valid
return valid
func passwords_valid(password, cpassword):
return password == cpassword and len(password) >= MIN_PASSWORD_LENGTH
func check_email(email) -> bool:
# Use regex to validate email
var regex = RegEx.new()
regex.compile("[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,6}")
var result = regex.search(email)
if result:
return true
return false

View File

@ -0,0 +1,31 @@
extends Node
const KEY := "defaultkey"
const SERVER_ENDPOINT := "nakama.cloudsumu.com"
var _session : NakamaSession
var _client : NakamaClient = Nakama.create_client(KEY, SERVER_ENDPOINT, 7350, "http")
func authenticate_async(email : String, password : String) -> NakamaException:
var result : NakamaException = null
var new_session : NakamaSession = yield(_client.authenticate_email_async(email, password, null, false), "completed")
if not new_session.is_exception():
_session = new_session
else:
result = new_session.get_exception()
return result
func signup_async(email : String, password : String) -> NakamaException:
var result : NakamaException = null
var new_session : NakamaSession = yield(_client.authenticate_email_async(email, password, null, true), "completed")
if not new_session.is_exception():
_session = new_session
else:
result = new_session.get_exception()
return result

View File

@ -1,4 +0,0 @@
extends "res://addons/gut/test.gd"
func test_example():
assert_true(true)

View File

@ -0,0 +1,55 @@
extends "res://addons/gut/test.gd"
var signup_form = load("res://scripts/menus/signup_form.gd")
# Test Object
var form = signup_form.new()
#------------
# Email Test
#------------
var valid_email_list = [
"untitled@gmail.com",
"test@cloudsumu.com",
"cool.game@tetraforce.io",
"ExampleName@yahoo.com"
]
var invalid_email_list = [
"test the test",
"test",
"test@test",
"gmail.com",
"google.com",
"@amazon.com",
"test@_.com",
"test@test.",
"Hello World!"
]
func test_check_email_with_valid_email():
for email in valid_email_list:
assert_true(form.check_email(email))
func test_check_email_with_invalid_email():
for email in invalid_email_list:
assert_false(form.check_email(email))
#---------------
# Password Test
#---------------
var valid_passwords = [
"Testing123!",
"gR8$cuP8kJ8%qk*t",
"GVa9%BZHh",
"2Uw@2*5Qb$Gflb@c",
"iL3DINd@hRaBlevo"
]
func test_passwords_valid_do_match():
for password in valid_passwords:
assert_true(form.passwords_valid(password, password))
func test_passwords_valid_do_not_match():
for password in valid_passwords:
assert_false(form.passwords_valid(password, null))