feat(scoreboard): get session coockie and api config file

This commit is contained in:
2025-10-30 00:20:09 +01:00
parent 1df26a6b28
commit 44b1f0b884
3 changed files with 100 additions and 20 deletions

3
.gitignore vendored
View File

@@ -17,3 +17,6 @@ addons/escoria-core/default_bus_layout.tres
addons/godot-plugin-refresher/
addons/script-ide/
build/
# API credentials
api.ini

View File

@@ -1,45 +1,123 @@
class_name RTMIScoreManager
extends Node
## Score manager to get and submit scores from and to Scoreboard web service.
const PERFECT = "perfect"
const FASTEST = "fastest"
const SUBMIT = "submit"
var url: String
var project_id: String
var database_id: String
var email: String
var password: String
var http_requests: Dictionary = {
PERFECT: HTTPRequest.new(),
FASTEST: HTTPRequest.new(),
SUBMIT: HTTPRequest.new(),
}
# Session cookie used for authentication. Needed for score submitting.
var session_cookie: String = ""
func _init(scene) -> void:
_load_api_config()
scene.add_child(http_requests[PERFECT])
scene.add_child(http_requests[FASTEST])
scene.add_child(http_requests[SUBMIT])
func _load_api_config() -> void:
var config = ConfigFile.new()
var error = config.load("res://api.ini")
if error != OK:
return
url = config.get_value("api", "url", "")
project_id = config.get_value("api", "project_id", "")
database_id = config.get_value("api", "database_id", "")
email = config.get_value("api", "email", "")
password = config.get_value("api", "password", "")
func get_scores(collection: String) -> Array[RTMIScoreRow]:
var http_request = http_requests[collection]
var data = await _score_http_request(http_request, "%s/databases/%s/collections/%s/documents" % [url, database_id, collection])
if collection == FASTEST:
submit_score()
if not data:
return []
# Map DB rows to RTMIScoreRow
var scores_untyped = data.get("documents").map(func(document): return RTMIScoreRow.new(document))
# Array.map() does not support typing, we need to use Array.assign to set the type.
var scores: Array[RTMIScoreRow]
scores.assign(scores_untyped)
return scores
func submit_score() -> void:
var session_cookie = await get_session_cookie(http_requests[SUBMIT])
push_error("SESSION COOKIE=%s" % session_cookie)
return
func get_session_cookie(http_request: HTTPRequest) -> String:
if session_cookie:
return session_cookie
var error = http_request.request(
"https://app.fosil.eu/v1/databases/68fff91900295af283bf/collections/%s/documents" % collection,
["X-Appwrite-Project: 68fff7ac0029558ca82c", "Content-Type: application/json"]
"%s/account/sessions/email" % url,
["X-Appwrite-Project: %s" % project_id, "Content-Type: application/json"],
HTTPClient.METHOD_POST,
'{"email":"%s","password":"%s"}' % [email, password]
)
if error != OK:
push_error("An error occurred creating the HTTP request: error=%s" % error)
return ""
var response: Array = await http_request.request_completed
return _http_request_completed.callv(response)
var result: int = response[0]
var http_status: int = response[1]
var response_headers: PackedStringArray = response[2]
func _http_request_completed(result: int, http_status: int, _headers: PackedStringArray, body: PackedByteArray) -> Array[RTMIScoreRow]:
if result != HTTPRequest.RESULT_SUCCESS or http_status < 200 or http_status >= 300:
push_error("HTTP request returned an error: result=%s http_status=%s" % [result, http_status])
return []
return ""
var response = JSON.parse_string(body.get_string_from_utf8())
if not response or not response.get("documents"):
var cookie_pos = Array(response_headers).find_custom(func(header: String): return header.to_lower().begins_with("set-cookie: "))
if cookie_pos < 0:
return ""
session_cookie = response_headers[cookie_pos].substr("set-cookie: ".length()).get_slice(";", 0)
return session_cookie
func _score_http_request(
http_request: HTTPRequest, url: String, method: int = HTTPClient.METHOD_GET, request_data: String = "", additional_headers: Array = []
) -> Variant:
var headers = ["X-Appwrite-Project: %s" % project_id, "Content-Type: application/json"]
headers.append_array(additional_headers)
var error = http_request.request(url, headers, method, request_data)
if error:
push_error("An error occurred creating the HTTP request: error=%s" % error)
return null
var response: Array = await http_request.request_completed
var result: int = response[0]
var http_status: int = response[1]
var body: PackedByteArray = response[3]
if result != HTTPRequest.RESULT_SUCCESS or http_status < 200 or http_status >= 300:
push_error("HTTP request returned an error: result=%s http_status=%s" % [result, http_status])
return null
var response_data = JSON.parse_string(body.get_string_from_utf8())
if not response_data:
push_error("Error parsing HTTP body.")
return []
var scores: Array[RTMIScoreRow] = []
for document in response.get("documents"):
scores.append(RTMIScoreRow.new(document))
return scores
return response_data

View File

@@ -1,5 +1,5 @@
extends ESCItemComponent
class_name ESCItemComponentOutline
extends ESCItemComponent
var outline: ItemOutline
@@ -24,15 +24,15 @@ func highlight(value: bool) -> void:
for node in get_parent().collision.get_children():
if node is ItemOutline:
node.visible = value
func _input(event) -> void:
if not event.is_action("ui_show_hints"):
return
if escoria.current_state != escoria.GAME_STATE.DEFAULT:
return
if not get_object().interactive:
if get_object() and not get_object().interactive:
return
# No tool selected
@@ -46,7 +46,7 @@ func _input(event) -> void:
# Only with tool selected
if escoria.action_manager.action_state != escoria.action_manager.ACTION_INPUT_STATE.AWAITING_TARGET_ITEM:
return
if not gymkhana.has_combination_with_current_tool(get_global_id()):
return
@@ -54,4 +54,3 @@ func _input(event) -> void:
highlight(true)
elif not gymkhana.is_item_under_mouse(get_global_id()):
highlight(false)