Add server-authoritative RZ Coin rewards

This commit is contained in:
hz
2026-08-01 01:28:38 -05:00
parent 8c439c6294
commit ddc36a8048
24 changed files with 670 additions and 104 deletions
+49
View File
@@ -5,6 +5,8 @@ signal credits_failed(message: String)
signal store_operation_completed(message: String)
signal spin_resolved(reward_key: String, reward_label: String, coins_won: int)
signal spin_config_loaded
signal award_received(amount: int, reason: String)
signal ledger_changed
const EndpointConfig := preload("res://scripts/autoload/api_endpoint_config.gd")
const DEFAULT_URL := "https://us3q.ranaze.com/api/credits"
@@ -21,9 +23,13 @@ var loading := false
var request: HTTPRequest
var action_request: HTTPRequest
var spin_config_request: HTTPRequest
var ledger_request: HTTPRequest
var request_token := ""
var api_url := DEFAULT_URL
var pending_store_action := ""
var ledger: Array = []
var ledger_next_before := ""
var ledger_append := false
func _ready() -> void:
@@ -42,6 +48,10 @@ func _ready() -> void:
spin_config_request.timeout = 20.0
spin_config_request.request_completed.connect(_on_spin_config_completed)
add_child(spin_config_request)
ledger_request = HTTPRequest.new()
ledger_request.timeout = 20.0
ledger_request.request_completed.connect(_on_ledger_completed)
add_child(ledger_request)
AuthState.auth_changed.connect(_on_auth_changed)
@@ -67,6 +77,43 @@ func apply_status(parsed: Dictionary) -> void:
credits_changed.emit()
func apply_award_response(parsed: Dictionary) -> void:
var status: Variant = parsed.get("credits", null)
if typeof(status) == TYPE_DICTIONARY:
apply_status(status)
for award_variant in parsed.get("creditAwards", []):
if typeof(award_variant) != TYPE_DICTIONARY:
continue
var award: Dictionary = award_variant
var amount := int(award.get("amount", 0))
if amount > 0:
award_received.emit(amount, str(award.get("description", "Learning reward")))
func load_ledger(before: String = "") -> void:
if not AuthState.can_send_authenticated_request() or ledger_request.get_http_client_status() != HTTPClient.STATUS_DISCONNECTED:
return
ledger_append = not before.is_empty()
var suffix := "/ledger?limit=20"
if not before.is_empty():
suffix += "&before=%s" % before.uri_encode()
ledger_request.request(api_url + suffix, PackedStringArray(["Authorization: Bearer %s" % AuthState.access_token]), HTTPClient.METHOD_GET)
func _on_ledger_completed(result: int, response_code: int, _headers: PackedStringArray, body: PackedByteArray) -> void:
if result != HTTPRequest.RESULT_SUCCESS or response_code < 200 or response_code >= 300:
credits_failed.emit("Coin history could not be loaded.")
return
var parsed: Variant = JSON.parse_string(body.get_string_from_utf8())
if typeof(parsed) != TYPE_DICTIONARY:
return
var items: Array = parsed.get("items", [])
ledger = ledger + items if ledger_append else items
var cursor: Variant = parsed.get("nextBefore", null)
ledger_next_before = "" if cursor == null else str(cursor)
ledger_changed.emit()
func _on_completed(result: int, response_code: int, _headers: PackedStringArray, body: PackedByteArray) -> void:
loading = false
if response_code == 401:
@@ -173,6 +220,8 @@ func _on_auth_changed() -> void:
bank_cycle = 0
products = []
spin_rewards = []
ledger = []
ledger_next_before = ""
loaded = false
loading = false
if request.get_http_client_status() != HTTPClient.STATUS_DISCONNECTED:
@@ -196,6 +196,7 @@ func _on_request_completed(result: int, response_code: int, _headers: PackedStri
last_failed_action = action
request_failed.emit("The simulation API returned an invalid response.")
return
CreditsService.apply_award_response(parsed)
if action == "readiness":
readiness = parsed
readiness_changed.emit()
+1 -3
View File
@@ -545,9 +545,7 @@ func _apply_first_attempt_response(parsed: Dictionary) -> void:
var rating: Dictionary = parsed.get("rating", {})
_update_question_elo(question_id, question_elo)
_apply_rating_change(rating)
var credits_status: Variant = parsed.get("credits", null)
if typeof(credits_status) == TYPE_DICTIONARY:
CreditsService.apply_status(credits_status)
CreditsService.apply_award_response(parsed)
choice_percentages_updated.emit(question_id, percentages)
question_rating_updated.emit(question_id, question_elo, rating)
+1
View File
@@ -190,6 +190,7 @@ func _on_attempt_completed(result: int, response_code: int, _headers_value: Pack
var synced_question_id := ""
var synced_is_correct := false
if typeof(parsed) == TYPE_DICTIONARY:
CreditsService.apply_award_response(parsed)
pending_count = int(parsed.get("pendingCount", parsed.get("pending_count", pending_count)))
synced_question_id = str(parsed.get("questionExternalId", parsed.get("question_external_id", "")))
synced_is_correct = bool(parsed.get("isCorrect", parsed.get("is_correct", false)))