refactor: harden client runtime and exports
This commit is contained in:
@@ -13,8 +13,6 @@ const CAMERA_LIMIT_LEFT: int = -538
|
||||
const CAMERA_LIMIT_TOP: int = -358
|
||||
const CAMERA_LIMIT_RIGHT: int = 538
|
||||
const CAMERA_LIMIT_BOTTOM: int = 358
|
||||
const NetworkConfig = preload("res://_Core/utils/NetworkConfig.gd")
|
||||
|
||||
const TEXT_COLOR: Color = Color(0.102, 0.224, 0.376)
|
||||
const PANEL_COLOR: Color = Color(0.970, 0.992, 1.0, 0.96)
|
||||
const ACCENT_COLOR: Color = Color(0.086, 0.608, 0.922)
|
||||
@@ -25,6 +23,8 @@ const DECOR_COLLISION_MASK: int = 1
|
||||
const ROOM_GRID_SIZE: float = 16.0
|
||||
const FLOOR_PLACE_BOUNDS: Rect2 = Rect2(-426.0, -176.0, 852.0, 388.0)
|
||||
const WALL_PLACE_BOUNDS: Rect2 = Rect2(-378.0, -258.0, 756.0, 66.0)
|
||||
const RoomDecorEditHistory = preload("res://_Core/room_decor/RoomDecorEditHistory.gd")
|
||||
const RoomDecorCollisionRegistry = preload("res://_Core/room_decor/RoomDecorCollisionRegistry.gd")
|
||||
|
||||
@onready var player: PlayerController = $YSortWorld/Characters/Players/Player
|
||||
@onready var playerCamera: Camera2D = $YSortWorld/Characters/Players/Player/Camera2D
|
||||
@@ -34,7 +34,6 @@ const WALL_PLACE_BOUNDS: Rect2 = Rect2(-378.0, -258.0, 756.0, 66.0)
|
||||
|
||||
var _decorLayer: Node2D
|
||||
var _gridOverlay: Node2D
|
||||
var _inventoryRequest: HTTPRequest
|
||||
var _inventoryPanel: PanelContainer
|
||||
var _inventoryGrid: GridContainer
|
||||
var _dragSurface: Control
|
||||
@@ -61,7 +60,7 @@ var _dragOriginalItem: Dictionary = {}
|
||||
var _decorItems: Dictionary = {}
|
||||
var _serverDecorItems: Dictionary = {}
|
||||
var _decorNodes: Dictionary = {}
|
||||
var _decorCollisionBodies: Dictionary = {}
|
||||
var _decorCollisionRegistry: RefCounted
|
||||
var _remoteDecorDefinitions: Dictionary = {}
|
||||
var _inventoryRequestInFlight: bool = false
|
||||
var _inventoryRequestReportsErrors: bool = false
|
||||
@@ -71,8 +70,7 @@ var _visitorOwnerId: String = ""
|
||||
var _visitorOwnerName: String = ""
|
||||
var _editMode: bool = false
|
||||
var _showPlacementGrid: bool = false
|
||||
var _undoHistory: Array[Dictionary] = []
|
||||
var _redoHistory: Array[Dictionary] = []
|
||||
var _editHistory: RefCounted = RoomDecorEditHistory.new()
|
||||
var _dirtyDecorIds: Dictionary = {}
|
||||
var _saveAwaitingIds: Dictionary = {}
|
||||
var _saveFailedIds: Dictionary = {}
|
||||
@@ -86,8 +84,8 @@ func _ready() -> void:
|
||||
_leave_multiplayer_world()
|
||||
_apply_spawn_point()
|
||||
_configure_camera()
|
||||
_decorCollisionRegistry = RoomDecorCollisionRegistry.new(staticCollision, DECOR_COLLISION_LAYER, DECOR_COLLISION_MASK)
|
||||
_build_decor_layer()
|
||||
_build_room_decor_requests()
|
||||
_build_room_decor_ui()
|
||||
_connect_room_decor_events()
|
||||
_fetch_room_decor_inventory()
|
||||
@@ -119,8 +117,8 @@ func _exit_tree() -> void:
|
||||
saveManager.decor_save_succeeded.disconnect(_on_decor_save_succeeded)
|
||||
if saveManager.decor_save_failed.is_connected(_on_decor_save_failed):
|
||||
saveManager.decor_save_failed.disconnect(_on_decor_save_failed)
|
||||
if is_instance_valid(_inventoryRequest):
|
||||
_inventoryRequest.cancel_request()
|
||||
if saveManager.decor_revision_conflict.is_connected(_on_decor_revision_conflict):
|
||||
saveManager.decor_revision_conflict.disconnect(_on_decor_revision_conflict)
|
||||
|
||||
func _input(event: InputEvent) -> void:
|
||||
if get_viewport().is_input_handled():
|
||||
@@ -237,13 +235,6 @@ func _add_grid_line(from: Vector2, to: Vector2, color: Color, width: float) -> v
|
||||
line.antialiased = true
|
||||
_gridOverlay.add_child(line)
|
||||
|
||||
func _build_room_decor_requests() -> void:
|
||||
_inventoryRequest = HTTPRequest.new()
|
||||
_inventoryRequest.name = "roomDecorInventoryRequest"
|
||||
_inventoryRequest.timeout = 12.0
|
||||
_inventoryRequest.request_completed.connect(_on_inventory_request_completed)
|
||||
add_child(_inventoryRequest)
|
||||
|
||||
func _build_room_decor_ui() -> void:
|
||||
_build_room_toolbar()
|
||||
_build_unsaved_exit_dialog()
|
||||
@@ -495,6 +486,8 @@ func _connect_room_decor_events() -> void:
|
||||
saveManager.decor_save_succeeded.connect(_on_decor_save_succeeded)
|
||||
if not saveManager.decor_save_failed.is_connected(_on_decor_save_failed):
|
||||
saveManager.decor_save_failed.connect(_on_decor_save_failed)
|
||||
if not saveManager.decor_revision_conflict.is_connected(_on_decor_revision_conflict):
|
||||
saveManager.decor_revision_conflict.connect(_on_decor_revision_conflict)
|
||||
|
||||
func _on_backpack_toggle_requested(_data: Variant = null) -> void:
|
||||
if _visitorMode:
|
||||
@@ -525,35 +518,22 @@ func _fetch_room_decor_inventory(reportErrors: bool = false) -> void:
|
||||
_inventoryRequestInFlight = true
|
||||
_inventoryRequestReportsErrors = reportErrors
|
||||
var endpoint: String = "/rooms/%s/decor-placements" % _visitorOwnerId if _visitorMode else "/rooms/me/decor-placements"
|
||||
var err := _inventoryRequest.request("%s%s" % [NetworkConfig.get_api_base_url(), endpoint], _auth_headers(), HTTPClient.METHOD_GET, "")
|
||||
if err != OK:
|
||||
var api_client := get_node_or_null("/root/ApiClient")
|
||||
if api_client == null or not api_client.has_method("get_json"):
|
||||
_inventoryRequestInFlight = false
|
||||
if _inventoryRequestReportsErrors:
|
||||
_show_toast("家具背包请求发送失败")
|
||||
_show_toast("家具背包服务不可用")
|
||||
_inventoryRequestReportsErrors = false
|
||||
return
|
||||
api_client.call("get_json", endpoint, _on_inventory_request_completed, true)
|
||||
|
||||
func _on_inventory_request_completed(result: int, responseCode: int, _headers: PackedStringArray, body: PackedByteArray) -> void:
|
||||
func _on_inventory_request_completed(success: bool, response: Dictionary, error_info: Dictionary) -> void:
|
||||
_inventoryRequestInFlight = false
|
||||
var reportErrors := _inventoryRequestReportsErrors
|
||||
_inventoryRequestReportsErrors = false
|
||||
if result != HTTPRequest.RESULT_SUCCESS or responseCode < 200 or responseCode >= 300:
|
||||
if not success:
|
||||
if reportErrors:
|
||||
_show_toast("家具背包读取失败")
|
||||
return
|
||||
var json := JSON.new()
|
||||
if json.parse(body.get_string_from_utf8()) != OK:
|
||||
if reportErrors:
|
||||
_show_toast("家具背包响应解析失败")
|
||||
return
|
||||
var responseVariant: Variant = json.data
|
||||
if not (responseVariant is Dictionary):
|
||||
if reportErrors:
|
||||
_show_toast("家具背包响应格式错误")
|
||||
return
|
||||
var response: Dictionary = responseVariant
|
||||
if not bool(response.get("success", true)):
|
||||
if reportErrors:
|
||||
_show_toast(str(response.get("message", "家具背包读取失败")))
|
||||
_show_toast(str(error_info.get("message", "家具背包读取失败")))
|
||||
return
|
||||
var dataVariant: Variant = response.get("data", {})
|
||||
if dataVariant is Dictionary:
|
||||
@@ -580,6 +560,9 @@ func _apply_inventory_payload(data: Dictionary) -> void:
|
||||
if not decorId.is_empty():
|
||||
_decorItems[decorId] = _merge_decor_definition(item)
|
||||
if not _visitorMode:
|
||||
var save_manager := get_node_or_null("/root/RoomDecorSaveManager")
|
||||
if save_manager != null and save_manager.has_method("set_layout_revision"):
|
||||
save_manager.call("set_layout_revision", int(data.get("revision", 0)), true)
|
||||
_serverDecorItems = _duplicate_item_map(_decorItems)
|
||||
_dirtyDecorIds.clear()
|
||||
_saveFailedIds.clear()
|
||||
@@ -946,6 +929,17 @@ func _on_decor_save_succeeded(savedItem: Dictionary) -> void:
|
||||
_render_inventory_list()
|
||||
_finalize_save_if_ready()
|
||||
|
||||
func _on_decor_revision_conflict(_current_revision: int, message: String) -> void:
|
||||
_saveAwaitingIds.clear()
|
||||
_saveFailedIds.clear()
|
||||
_saveInProgress = false
|
||||
_exitAfterSave = false
|
||||
_dirtyDecorIds.clear()
|
||||
_editHistory.call("clear")
|
||||
_update_editor_toolbar()
|
||||
_show_toast(message)
|
||||
_fetch_room_decor_inventory(true)
|
||||
|
||||
func _can_edit_layout() -> bool:
|
||||
return not _visitorMode and _editMode and not _saveInProgress
|
||||
|
||||
@@ -959,8 +953,7 @@ func _set_edit_mode(enabled: bool) -> void:
|
||||
return
|
||||
_editMode = true
|
||||
_selectedDecorId = ""
|
||||
_undoHistory.clear()
|
||||
_redoHistory.clear()
|
||||
_editHistory.call("clear")
|
||||
_resetArmed = false
|
||||
_showPlacementGrid = false
|
||||
_update_placement_grid_visibility()
|
||||
@@ -984,8 +977,7 @@ func _request_finish_edit() -> void:
|
||||
func _end_edit_session() -> void:
|
||||
_editMode = false
|
||||
_selectedDecorId = ""
|
||||
_undoHistory.clear()
|
||||
_redoHistory.clear()
|
||||
_editHistory.call("clear")
|
||||
_resetArmed = false
|
||||
_exitAfterSave = false
|
||||
_showPlacementGrid = false
|
||||
@@ -1038,10 +1030,10 @@ func _update_editor_toolbar() -> void:
|
||||
_finishEditButton.disabled = _saveInProgress
|
||||
if is_instance_valid(_undoButton):
|
||||
_undoButton.visible = _editMode
|
||||
_undoButton.disabled = not _can_edit_layout() or _undoHistory.is_empty()
|
||||
_undoButton.disabled = not _can_edit_layout() or not bool(_editHistory.call("can_undo"))
|
||||
if is_instance_valid(_redoButton):
|
||||
_redoButton.visible = _editMode
|
||||
_redoButton.disabled = not _can_edit_layout() or _redoHistory.is_empty()
|
||||
_redoButton.disabled = not _can_edit_layout() or not bool(_editHistory.call("can_redo"))
|
||||
if is_instance_valid(_rotateButton):
|
||||
_rotateButton.visible = _editMode
|
||||
_rotateButton.disabled = not _can_edit_layout() or not selected_is_placed
|
||||
@@ -1086,43 +1078,25 @@ func _update_placement_grid_visibility() -> void:
|
||||
_gridOverlay.visible = _editMode and _showPlacementGrid
|
||||
|
||||
func _record_item_change(before: Dictionary, after: Dictionary) -> void:
|
||||
if before == after:
|
||||
return
|
||||
var decor_id: String = str(after.get("decor_id", before.get("decor_id", ""))).strip_edges()
|
||||
if decor_id.is_empty():
|
||||
return
|
||||
_undoHistory.append({
|
||||
"decor_id": decor_id,
|
||||
"before": before.duplicate(true),
|
||||
"after": after.duplicate(true),
|
||||
})
|
||||
_redoHistory.clear()
|
||||
_update_editor_toolbar()
|
||||
if bool(_editHistory.call("record_item", before, after)):
|
||||
_update_editor_toolbar()
|
||||
|
||||
func _record_bulk_change(before_items: Dictionary, after_items: Dictionary) -> void:
|
||||
if before_items == after_items:
|
||||
return
|
||||
_undoHistory.append({
|
||||
"before_items": _duplicate_item_map(before_items),
|
||||
"after_items": _duplicate_item_map(after_items),
|
||||
})
|
||||
_redoHistory.clear()
|
||||
_update_editor_toolbar()
|
||||
if bool(_editHistory.call("record_bulk", before_items, after_items)):
|
||||
_update_editor_toolbar()
|
||||
|
||||
func _undo_last_change() -> void:
|
||||
if not _can_edit_layout() or _undoHistory.is_empty():
|
||||
if not _can_edit_layout() or not bool(_editHistory.call("can_undo")):
|
||||
return
|
||||
var entry: Dictionary = _undoHistory.pop_back()
|
||||
var entry: Dictionary = _editHistory.call("take_undo")
|
||||
_apply_history_entry(entry, false)
|
||||
_redoHistory.append(entry)
|
||||
_update_editor_toolbar()
|
||||
|
||||
func _redo_last_change() -> void:
|
||||
if not _can_edit_layout() or _redoHistory.is_empty():
|
||||
if not _can_edit_layout() or not bool(_editHistory.call("can_redo")):
|
||||
return
|
||||
var entry: Dictionary = _redoHistory.pop_back()
|
||||
var entry: Dictionary = _editHistory.call("take_redo")
|
||||
_apply_history_entry(entry, true)
|
||||
_undoHistory.append(entry)
|
||||
_update_editor_toolbar()
|
||||
|
||||
func _apply_history_entry(entry: Dictionary, use_after: bool) -> void:
|
||||
@@ -1190,6 +1164,9 @@ func _request_reset_layout() -> void:
|
||||
get_tree().create_timer(3.0).timeout.connect(func() -> void: _resetArmed = false)
|
||||
return
|
||||
_resetArmed = false
|
||||
var save_manager := get_node_or_null("/root/RoomDecorSaveManager")
|
||||
if save_manager != null and save_manager.has_method("clear_pending_saves"):
|
||||
save_manager.call("clear_pending_saves")
|
||||
var before_items := _duplicate_item_map(_decorItems)
|
||||
for decor_id_variant in _decorItems.keys():
|
||||
var decor_id := str(decor_id_variant)
|
||||
@@ -1411,56 +1388,16 @@ func _is_point_inside_sprite(node: Sprite2D, worldPosition: Vector2) -> bool:
|
||||
return rect.has_point(localPoint)
|
||||
|
||||
func _sync_decor_collision(decorId: String, item: Dictionary) -> void:
|
||||
var collisionSize := _variant_to_vector2(item.get("collision_size", Vector2.ZERO))
|
||||
if collisionSize == Vector2.ZERO:
|
||||
_remove_decor_collision(decorId)
|
||||
return
|
||||
var collisionOffset := _variant_to_vector2(item.get("collision_offset", Vector2.ZERO))
|
||||
var body := _decorCollisionBodies.get(decorId, null) as StaticBody2D
|
||||
var shapeNode: CollisionShape2D
|
||||
if body == null or not is_instance_valid(body):
|
||||
body = StaticBody2D.new()
|
||||
body.name = "DecorCollision_%s" % decorId
|
||||
body.collision_layer = DECOR_COLLISION_LAYER
|
||||
body.collision_mask = DECOR_COLLISION_MASK
|
||||
shapeNode = CollisionShape2D.new()
|
||||
shapeNode.name = "CollisionShape2D"
|
||||
var rectShape := RectangleShape2D.new()
|
||||
shapeNode.shape = rectShape
|
||||
body.add_child(shapeNode)
|
||||
staticCollision.add_child(body)
|
||||
_decorCollisionBodies[decorId] = body
|
||||
else:
|
||||
shapeNode = body.get_node_or_null("CollisionShape2D") as CollisionShape2D
|
||||
if shapeNode == null:
|
||||
shapeNode = CollisionShape2D.new()
|
||||
shapeNode.name = "CollisionShape2D"
|
||||
shapeNode.shape = RectangleShape2D.new()
|
||||
body.add_child(shapeNode)
|
||||
var scale := _get_item_float(item, "scale", _get_item_float(item, "default_scale", 1.0))
|
||||
var rotation_degrees := _get_item_float(item, "rotation_degrees", _get_item_float(item, "default_rotation_degrees", 0.0))
|
||||
body.rotation_degrees = rotation_degrees
|
||||
body.global_position = Vector2(_to_float(item.get("position_x", 0.0), 0.0), _to_float(item.get("position_y", 0.0), 0.0)) + collisionOffset.rotated(deg_to_rad(rotation_degrees)) * scale
|
||||
shapeNode.position = Vector2.ZERO
|
||||
var rectShape := shapeNode.shape as RectangleShape2D
|
||||
if rectShape == null:
|
||||
rectShape = RectangleShape2D.new()
|
||||
shapeNode.shape = rectShape
|
||||
rectShape.size = Vector2(max(8.0, collisionSize.x * scale), max(8.0, collisionSize.y * scale))
|
||||
if _decorCollisionRegistry != null:
|
||||
_decorCollisionRegistry.call("sync", decorId, item)
|
||||
|
||||
func _set_decor_collision_disabled(decorId: String, disabled: bool) -> void:
|
||||
var body := _decorCollisionBodies.get(decorId, null) as StaticBody2D
|
||||
if body == null or not is_instance_valid(body):
|
||||
return
|
||||
var shapeNode := body.get_node_or_null("CollisionShape2D") as CollisionShape2D
|
||||
if shapeNode != null:
|
||||
shapeNode.disabled = disabled
|
||||
if _decorCollisionRegistry != null:
|
||||
_decorCollisionRegistry.call("set_disabled", decorId, disabled)
|
||||
|
||||
func _remove_decor_collision(decorId: String) -> void:
|
||||
var body := _decorCollisionBodies.get(decorId, null) as Node
|
||||
if body != null and is_instance_valid(body):
|
||||
body.queue_free()
|
||||
_decorCollisionBodies.erase(decorId)
|
||||
if _decorCollisionRegistry != null:
|
||||
_decorCollisionRegistry.call("remove", decorId)
|
||||
|
||||
func _variant_to_vector2(value: Variant) -> Vector2:
|
||||
if value is Vector2:
|
||||
@@ -1508,14 +1445,6 @@ func _is_authenticated() -> bool:
|
||||
var authManager := get_node_or_null("/root/AuthManager")
|
||||
return authManager != null and authManager.has_method("is_authenticated") and bool(authManager.call("is_authenticated"))
|
||||
|
||||
func _auth_headers() -> PackedStringArray:
|
||||
var authManager := get_node_or_null("/root/AuthManager")
|
||||
var accessToken := str(authManager.call("get_access_token")).strip_edges() if authManager != null and authManager.has_method("get_access_token") else ""
|
||||
return PackedStringArray([
|
||||
"Content-Type: application/json",
|
||||
"Authorization: Bearer %s" % accessToken,
|
||||
])
|
||||
|
||||
func _load_texture(path: String) -> Texture2D:
|
||||
if path.is_empty():
|
||||
return null
|
||||
|
||||
@@ -25,7 +25,6 @@ const REGISTRATION_CHOICE_SPRITESHEET_GRID_BOX_PATH: String = REGISTRATION_CHOIC
|
||||
const REGISTRATION_CHOICE_REFERENCE_UPLOAD_BOX_PATH: String = REGISTRATION_CHOICE_ASSET_DIR + "/reference_upload_box.png"
|
||||
const REGISTRATION_CHOICE_IMAGE_PLACEHOLDER_BOX_PATH: String = REGISTRATION_CHOICE_ASSET_DIR + "/image_placeholder_box.png"
|
||||
const UI_FONT_PATH: String = "res://assets/fonts/msyh.ttc"
|
||||
const NetworkConfig = preload("res://_Core/utils/NetworkConfig.gd")
|
||||
const SKIN_GENERATION_CREATE_ENDPOINT: String = "/api/skin-generation/jobs"
|
||||
const SKIN_GENERATION_POLL_ENDPOINT_TEMPLATE: String = "/api/skin-generation/jobs/%s"
|
||||
const SKIN_GENERATION_POLL_INTERVAL: float = 2.0
|
||||
@@ -94,8 +93,6 @@ var _brand_font: SystemFont
|
||||
var _choice_font: SystemFont
|
||||
var _resuming_cached_session: bool = false
|
||||
var _cached_resume_start_generation: int = 0
|
||||
var _skin_generation_create_request: HTTPRequest
|
||||
var _skin_generation_poll_request: HTTPRequest
|
||||
var _skin_generation_active: bool = false
|
||||
var _skin_generation_job_id: String = ""
|
||||
var _skin_generation_poll_elapsed: float = 0.0
|
||||
@@ -686,7 +683,6 @@ func _ready() -> void:
|
||||
_scene_manager = get_node_or_null("/root/SceneManager")
|
||||
_appearance_manager = get_node_or_null("/root/AppearanceManager")
|
||||
|
||||
_setup_skin_generation_requests()
|
||||
_connect_signals()
|
||||
_refresh_appearance_ui()
|
||||
_show_login()
|
||||
@@ -727,19 +723,6 @@ func _connect_signals() -> void:
|
||||
_auth_manager.connect("profile_update_failed", _on_profile_update_failed)
|
||||
_auth_manager.connect("auth_state_changed", _on_auth_state_changed)
|
||||
|
||||
func _setup_skin_generation_requests() -> void:
|
||||
_skin_generation_create_request = HTTPRequest.new()
|
||||
_skin_generation_create_request.name = "SkinGenerationCreateRequest"
|
||||
_skin_generation_create_request.timeout = SKIN_GENERATION_REQUEST_TIMEOUT
|
||||
_skin_generation_create_request.request_completed.connect(_on_skin_generation_create_completed)
|
||||
add_child(_skin_generation_create_request)
|
||||
|
||||
_skin_generation_poll_request = HTTPRequest.new()
|
||||
_skin_generation_poll_request.name = "SkinGenerationPollRequest"
|
||||
_skin_generation_poll_request.timeout = SKIN_GENERATION_REQUEST_TIMEOUT
|
||||
_skin_generation_poll_request.request_completed.connect(_on_skin_generation_poll_completed)
|
||||
add_child(_skin_generation_poll_request)
|
||||
|
||||
func _process(delta: float) -> void:
|
||||
if not _skin_generation_active or _skin_generation_job_id.is_empty():
|
||||
return
|
||||
@@ -749,10 +732,6 @@ func _process(delta: float) -> void:
|
||||
_poll_skin_generation_job()
|
||||
|
||||
func _exit_tree() -> void:
|
||||
if is_instance_valid(_skin_generation_create_request):
|
||||
_skin_generation_create_request.cancel_request()
|
||||
if is_instance_valid(_skin_generation_poll_request):
|
||||
_skin_generation_poll_request.cancel_request()
|
||||
_skin_generation_active = false
|
||||
_skin_generation_job_id = ""
|
||||
|
||||
@@ -1402,23 +1381,27 @@ func _on_generate_skin_pressed() -> void:
|
||||
"source_image_base64": _image_to_png_base64(sourceImage),
|
||||
"source_mime_type": "image/png",
|
||||
}
|
||||
var err := _skin_generation_create_request.request(
|
||||
"%s%s" % [NetworkConfig.get_api_base_url(), SKIN_GENERATION_CREATE_ENDPOINT],
|
||||
_auth_json_headers(),
|
||||
var api_client := get_node_or_null("/root/ApiClient")
|
||||
if api_client == null or not api_client.has_method("request_json"):
|
||||
_skin_generation_active = false
|
||||
_set_skin_generation_controls_enabled(true)
|
||||
_set_workshop_generation_status("角色生成服务不可用")
|
||||
return
|
||||
api_client.call(
|
||||
"request_json",
|
||||
SKIN_GENERATION_CREATE_ENDPOINT,
|
||||
payload,
|
||||
_on_skin_generation_create_completed,
|
||||
HTTPClient.METHOD_POST,
|
||||
JSON.stringify(payload)
|
||||
true,
|
||||
SKIN_GENERATION_REQUEST_TIMEOUT
|
||||
)
|
||||
if err != OK:
|
||||
_skin_generation_active = false
|
||||
_set_skin_generation_controls_enabled(true)
|
||||
_set_workshop_generation_status("角色生成请求发送失败:%s" % error_string(err))
|
||||
|
||||
func _on_skin_generation_create_completed(result: int, responseCode: int, _headers: PackedStringArray, body: PackedByteArray) -> void:
|
||||
var parsed := _parse_skin_generation_response(result, responseCode, body)
|
||||
if not bool(parsed.get("ok", false)):
|
||||
func _on_skin_generation_create_completed(success: bool, response: Dictionary, error_info: Dictionary) -> void:
|
||||
if not success:
|
||||
_skin_generation_active = false
|
||||
_set_skin_generation_controls_enabled(true)
|
||||
var errorMessage := str(parsed.get("message", "角色生成任务创建失败"))
|
||||
var errorMessage := str(error_info.get("message", "角色生成任务创建失败"))
|
||||
if errorMessage.contains("已经使用过注册角色生成机会") or errorMessage.contains("没有可用的注册角色生成机会"):
|
||||
_awaiting_registration_skin_generation = false
|
||||
_set_workshop_generation_status("该账号已完成注册角色生成,正在进入小镇...")
|
||||
@@ -1427,7 +1410,8 @@ func _on_skin_generation_create_completed(result: int, responseCode: int, _heade
|
||||
_set_workshop_generation_status(errorMessage)
|
||||
return
|
||||
|
||||
var data: Dictionary = parsed.get("data", {})
|
||||
var data_variant: Variant = response.get("data", {})
|
||||
var data: Dictionary = data_variant as Dictionary if data_variant is Dictionary else {}
|
||||
_skin_generation_job_id = str(data.get("job_id", "")).strip_edges()
|
||||
if _skin_generation_job_id.is_empty():
|
||||
_skin_generation_active = false
|
||||
@@ -1443,26 +1427,33 @@ func _poll_skin_generation_job() -> void:
|
||||
|
||||
_skin_generation_poll_in_flight = true
|
||||
var endpoint := SKIN_GENERATION_POLL_ENDPOINT_TEMPLATE % _skin_generation_job_id
|
||||
var err := _skin_generation_poll_request.request(
|
||||
"%s%s" % [NetworkConfig.get_api_base_url(), endpoint],
|
||||
_auth_json_headers(),
|
||||
HTTPClient.METHOD_GET
|
||||
)
|
||||
if err != OK:
|
||||
var api_client := get_node_or_null("/root/ApiClient")
|
||||
if api_client == null or not api_client.has_method("request_json"):
|
||||
_skin_generation_poll_in_flight = false
|
||||
_set_workshop_generation_status("查询生成状态失败:%s" % error_string(err))
|
||||
_set_workshop_generation_status("角色生成服务不可用")
|
||||
return
|
||||
api_client.call(
|
||||
"request_json",
|
||||
endpoint,
|
||||
{},
|
||||
_on_skin_generation_poll_completed,
|
||||
HTTPClient.METHOD_GET,
|
||||
true,
|
||||
SKIN_GENERATION_REQUEST_TIMEOUT
|
||||
)
|
||||
|
||||
func _on_skin_generation_poll_completed(result: int, responseCode: int, _headers: PackedStringArray, body: PackedByteArray) -> void:
|
||||
func _on_skin_generation_poll_completed(success: bool, response: Dictionary, error_info: Dictionary) -> void:
|
||||
_skin_generation_poll_in_flight = false
|
||||
var parsed := _parse_skin_generation_response(result, responseCode, body)
|
||||
if not bool(parsed.get("ok", false)):
|
||||
if responseCode == 401 or responseCode == 403 or responseCode == 404:
|
||||
if not success:
|
||||
var response_code := int(error_info.get("response_code", 0))
|
||||
if response_code == 401 or response_code == 403 or response_code == 404:
|
||||
_skin_generation_active = false
|
||||
_set_skin_generation_controls_enabled(true)
|
||||
_set_workshop_generation_status(str(parsed.get("message", "查询生成状态失败")))
|
||||
_set_workshop_generation_status(str(error_info.get("message", "查询生成状态失败")))
|
||||
return
|
||||
|
||||
var data: Dictionary = parsed.get("data", {})
|
||||
var data_variant: Variant = response.get("data", {})
|
||||
var data: Dictionary = data_variant as Dictionary if data_variant is Dictionary else {}
|
||||
var status := str(data.get("status", "")).strip_edges()
|
||||
var message := str(data.get("message", "")).strip_edges()
|
||||
if not message.is_empty():
|
||||
@@ -1548,73 +1539,6 @@ func _set_skin_generation_controls_enabled(enabled: bool) -> void:
|
||||
if is_instance_valid(workshop_generate_button):
|
||||
workshop_generate_button.disabled = not enabled
|
||||
|
||||
func _json_headers() -> PackedStringArray:
|
||||
return PackedStringArray([
|
||||
"Content-Type: application/json",
|
||||
"Accept: application/json",
|
||||
])
|
||||
|
||||
func _auth_json_headers() -> PackedStringArray:
|
||||
var headers := _json_headers()
|
||||
if _auth_manager != null and _auth_manager.has_method("get_access_token"):
|
||||
var token := str(_auth_manager.call("get_access_token")).strip_edges()
|
||||
if not token.is_empty():
|
||||
headers.append("Authorization: Bearer %s" % token)
|
||||
return headers
|
||||
|
||||
func _parse_skin_generation_response(result: int, responseCode: int, body: PackedByteArray) -> Dictionary:
|
||||
if result != HTTPRequest.RESULT_SUCCESS:
|
||||
return {
|
||||
"ok": false,
|
||||
"message": "网络请求失败:%s" % _http_result_to_string(result),
|
||||
}
|
||||
|
||||
var bodyText := body.get_string_from_utf8()
|
||||
var json := JSON.new()
|
||||
var error := json.parse(bodyText)
|
||||
if error != OK or not (json.data is Dictionary):
|
||||
return {
|
||||
"ok": false,
|
||||
"message": "服务器响应解析失败",
|
||||
}
|
||||
|
||||
var response: Dictionary = json.data as Dictionary
|
||||
var success := responseCode >= 200 and responseCode < 300 and bool(response.get("success", true))
|
||||
if not success:
|
||||
return {
|
||||
"ok": false,
|
||||
"message": str(response.get("message", "请求失败")),
|
||||
"response_code": responseCode,
|
||||
}
|
||||
|
||||
var dataVariant: Variant = response.get("data", response)
|
||||
if not (dataVariant is Dictionary):
|
||||
return {
|
||||
"ok": false,
|
||||
"message": "服务器响应格式错误",
|
||||
}
|
||||
|
||||
return {
|
||||
"ok": true,
|
||||
"data": dataVariant as Dictionary,
|
||||
}
|
||||
|
||||
func _http_result_to_string(result: int) -> String:
|
||||
match result:
|
||||
HTTPRequest.RESULT_SUCCESS:
|
||||
return "SUCCESS"
|
||||
HTTPRequest.RESULT_TIMEOUT:
|
||||
return "TIMEOUT"
|
||||
HTTPRequest.RESULT_CANT_CONNECT:
|
||||
return "CANT_CONNECT"
|
||||
HTTPRequest.RESULT_CANT_RESOLVE:
|
||||
return "CANT_RESOLVE"
|
||||
HTTPRequest.RESULT_CONNECTION_ERROR:
|
||||
return "CONNECTION_ERROR"
|
||||
HTTPRequest.RESULT_TLS_HANDSHAKE_ERROR:
|
||||
return "TLS_HANDSHAKE_ERROR"
|
||||
_:
|
||||
return "UNKNOWN_%d" % result
|
||||
|
||||
func _hide_skin_workshop() -> void:
|
||||
if _awaiting_registration_skin_generation:
|
||||
|
||||
@@ -8,8 +8,8 @@ extends Control
|
||||
# ============================================================================
|
||||
|
||||
const MOVEMENT_ACTIONS: Array[String] = ["move_left", "move_right", "move_up", "move_down"]
|
||||
const NetworkConfig = preload("res://_Core/utils/NetworkConfig.gd")
|
||||
const API_PATH: String = "/course-resources/datawhale"
|
||||
const REQUEST_TIMEOUT: float = 18.0
|
||||
const PANEL_SIZE: Vector2 = Vector2(1500, 1020)
|
||||
const MIN_MARGIN: Vector2 = Vector2(24, 24)
|
||||
const CARD_SIZE: Vector2 = Vector2(320, 348)
|
||||
@@ -24,7 +24,6 @@ var _overlay: ColorRect
|
||||
var _panel: Control
|
||||
var _grid: GridContainer
|
||||
var _statusLabel: Label
|
||||
var _request: HTTPRequest
|
||||
var _isOpen: bool = false
|
||||
var _transitionTween: Tween
|
||||
|
||||
@@ -124,10 +123,6 @@ func _buildUi() -> void:
|
||||
root.add_child(_buildGridPanel())
|
||||
root.add_child(_buildFooter())
|
||||
|
||||
_request = HTTPRequest.new()
|
||||
_request.timeout = 18.0
|
||||
_request.request_completed.connect(_onRequestCompleted)
|
||||
add_child(_request)
|
||||
_updatePanelAlpha(0.0, 0.0)
|
||||
|
||||
func _buildHeader() -> Control:
|
||||
@@ -222,23 +217,15 @@ func _buildFooter() -> Control:
|
||||
func _fetchCourses() -> void:
|
||||
_statusLabel.text = "正在同步 Datawhale 课程..."
|
||||
_clearChildren(_grid)
|
||||
var err := _request.request("%s%s" % [NetworkConfig.get_api_base_url(), API_PATH])
|
||||
if err != OK:
|
||||
_statusLabel.text = "课程加载失败:%s" % error_string(err)
|
||||
|
||||
func _onRequestCompleted(result: int, responseCode: int, _headers: PackedStringArray, body: PackedByteArray) -> void:
|
||||
if result != HTTPRequest.RESULT_SUCCESS or responseCode < 200 or responseCode >= 300:
|
||||
_statusLabel.text = "课程加载失败,请稍后再试"
|
||||
var api_client := get_node_or_null("/root/ApiClient")
|
||||
if api_client == null or not api_client.has_method("get_json"):
|
||||
_statusLabel.text = "课程服务不可用"
|
||||
return
|
||||
api_client.call("get_json", API_PATH, _onRequestCompleted, false, REQUEST_TIMEOUT)
|
||||
|
||||
var parsed: Variant = JSON.parse_string(body.get_string_from_utf8())
|
||||
if not parsed is Dictionary:
|
||||
_statusLabel.text = "课程数据解析失败"
|
||||
return
|
||||
|
||||
var payload: Dictionary = parsed as Dictionary
|
||||
if not bool(payload.get("success", true)):
|
||||
_statusLabel.text = str(payload.get("message", "课程加载失败"))
|
||||
func _onRequestCompleted(success: bool, payload: Dictionary, error_info: Dictionary) -> void:
|
||||
if not success:
|
||||
_statusLabel.text = str(error_info.get("message", "课程加载失败,请稍后再试"))
|
||||
return
|
||||
|
||||
var data: Variant = payload.get("data", {})
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
extends CanvasLayer
|
||||
class_name DatawhaleHonorRankingPanel
|
||||
|
||||
const NetworkConfig = preload("res://_Core/utils/NetworkConfig.gd")
|
||||
const TEX_PANEL_FRAME = preload("res://assets/ui/datawhale_honor/honor_panel_wood_frame.png")
|
||||
const TEX_WINDOW_SHELL = preload("res://assets/ui/datawhale_honor/honor_window_shell.png")
|
||||
const TEX_PARCHMENT_PANEL = preload("res://assets/ui/datawhale_honor/honor_parchment_panel.png")
|
||||
@@ -37,6 +36,7 @@ const TEX_AVATAR_FALLBACK_3 = preload("res://assets/ui/auth/generated/auth_chara
|
||||
const API_PATH: String = "/rankings/datawhale-honor"
|
||||
const PANEL_SIZE: Vector2 = Vector2(1500, 850)
|
||||
const REQUEST_LIMIT: int = 9
|
||||
const REQUEST_TIMEOUT: float = 18.0
|
||||
const LOWER_RANK_LIMIT: int = 6
|
||||
const LOWER_RANK_SLOT_HEIGHT: float = 45.0
|
||||
const LOWER_RANK_AVATAR_SIZE: float = 30.0
|
||||
@@ -85,8 +85,8 @@ var _podiumRow: Control
|
||||
var _rankList: VBoxContainer
|
||||
var _footerLabel: Label
|
||||
var _statusLabel: Label
|
||||
var _request: HTTPRequest
|
||||
var _avatarRequests: Array[HTTPRequest] = []
|
||||
var _rankingRequestGeneration: int = 0
|
||||
var _chatUi: Control
|
||||
var _chatUiPrevMouseFilter: Control.MouseFilter = Control.MOUSE_FILTER_STOP
|
||||
var _chatUiMouseDisabled: bool = false
|
||||
@@ -186,10 +186,6 @@ func _buildUi() -> void:
|
||||
_panel.add_child(_buildRuleOverlay())
|
||||
_panel.add_child(_buildCloseButton())
|
||||
|
||||
_request = HTTPRequest.new()
|
||||
_request.timeout = 18.0
|
||||
_request.request_completed.connect(_onRequestCompleted)
|
||||
add_child(_request)
|
||||
_setLoadingState()
|
||||
|
||||
func _buildBoardBody() -> Control:
|
||||
@@ -252,38 +248,28 @@ func _positionPanel() -> void:
|
||||
_panel.position = (viewportSize - PANEL_SIZE * scaleFactor) * 0.5
|
||||
|
||||
func _fetchRanking(categoryId: String) -> void:
|
||||
if _request == null:
|
||||
return
|
||||
if _isLoading:
|
||||
_request.cancel_request()
|
||||
_activeCategory = categoryId
|
||||
_isLoading = true
|
||||
_rankingRequestGeneration += 1
|
||||
_setLoadingState()
|
||||
var endpoint := "%s%s?category=%s&limit=%d&refresh=true" % [
|
||||
NetworkConfig.get_api_base_url(),
|
||||
var endpoint := "%s?category=%s&limit=%d&refresh=true" % [
|
||||
API_PATH,
|
||||
_urlEncode(_activeCategory),
|
||||
REQUEST_LIMIT,
|
||||
]
|
||||
var err := _request.request(endpoint, PackedStringArray(), HTTPClient.METHOD_GET, "")
|
||||
if err != OK:
|
||||
var api_client := get_node_or_null("/root/ApiClient")
|
||||
if api_client == null or not api_client.has_method("get_json"):
|
||||
_isLoading = false
|
||||
_setErrorState("荣誉榜请求失败:%s" % error_string(err))
|
||||
_setErrorState("荣誉榜服务不可用")
|
||||
return
|
||||
api_client.call("get_json", endpoint, Callable(self, "_onRequestCompleted").bind(_rankingRequestGeneration), false, REQUEST_TIMEOUT)
|
||||
|
||||
func _onRequestCompleted(result: int, responseCode: int, _headers: PackedStringArray, body: PackedByteArray) -> void:
|
||||
func _onRequestCompleted(success: bool, payload: Dictionary, error_info: Dictionary, request_generation: int) -> void:
|
||||
if request_generation != _rankingRequestGeneration:
|
||||
return
|
||||
_isLoading = false
|
||||
if result != HTTPRequest.RESULT_SUCCESS or responseCode < 200 or responseCode >= 300:
|
||||
_setErrorState("荣誉榜加载失败,请稍后再试")
|
||||
return
|
||||
|
||||
var parsed: Variant = JSON.parse_string(body.get_string_from_utf8())
|
||||
if not parsed is Dictionary:
|
||||
_setErrorState("荣誉榜数据解析失败")
|
||||
return
|
||||
|
||||
var payload := parsed as Dictionary
|
||||
if not bool(payload.get("success", true)):
|
||||
_setErrorState(str(payload.get("message", "荣誉榜加载失败")))
|
||||
if not success:
|
||||
_setErrorState(str(error_info.get("message", "荣誉榜加载失败,请稍后再试")))
|
||||
return
|
||||
|
||||
var dataVariant: Variant = payload.get("data", {})
|
||||
|
||||
@@ -20,7 +20,6 @@ const MALL_BADGE_TEXTURE: Texture2D = preload("res://assets/ui/mall/branding/bra
|
||||
const COIN_TEXTURE: Texture2D = preload("res://assets/ui/mall/branding/branding_whale_coin.png")
|
||||
const CATALOG_SCRIPT: Script = preload("res://Config/MallCatalog.gd")
|
||||
const ITEM_CARD_SCRIPT: Script = preload("res://scenes/ui/mall/MallItemCard.gd")
|
||||
const NetworkConfig = preload("res://_Core/utils/NetworkConfig.gd")
|
||||
|
||||
var _overlay: ColorRect
|
||||
var _panel: Control
|
||||
@@ -39,8 +38,6 @@ var _toastLabel: Label
|
||||
var _confirmDialog: Control
|
||||
var _confirmLabel: Label
|
||||
var _currencyLabel: Label
|
||||
var _purchaseRequest: HTTPRequest
|
||||
var _catalogRequest: HTTPRequest
|
||||
|
||||
var _categoryButtons: Dictionary = {}
|
||||
var _cards: Array[Button] = []
|
||||
@@ -175,8 +172,6 @@ func _build_ui() -> void:
|
||||
|
||||
_build_toast()
|
||||
_build_confirm_dialog()
|
||||
_build_purchase_request()
|
||||
_build_catalog_request()
|
||||
_update_panel_alpha(0.0, 0.0)
|
||||
|
||||
func _build_header() -> Control:
|
||||
@@ -859,20 +854,6 @@ func _format_item_price(item: Dictionary) -> String:
|
||||
func _is_skin_item(item: Dictionary) -> bool:
|
||||
return not str(item.get("skinId", "")).strip_edges().is_empty()
|
||||
|
||||
func _build_purchase_request() -> void:
|
||||
_purchaseRequest = HTTPRequest.new()
|
||||
_purchaseRequest.name = "mallPurchaseRequest"
|
||||
_purchaseRequest.timeout = 12.0
|
||||
_purchaseRequest.request_completed.connect(_on_purchase_request_completed)
|
||||
add_child(_purchaseRequest)
|
||||
|
||||
func _build_catalog_request() -> void:
|
||||
_catalogRequest = HTTPRequest.new()
|
||||
_catalogRequest.name = "mallCatalogRequest"
|
||||
_catalogRequest.timeout = 12.0
|
||||
_catalogRequest.request_completed.connect(_on_catalog_request_completed)
|
||||
add_child(_catalogRequest)
|
||||
|
||||
func _connect_auth_state() -> void:
|
||||
var authManager := get_node_or_null("/root/AuthManager")
|
||||
if authManager == null or not authManager.has_signal("auth_state_changed"):
|
||||
@@ -907,10 +888,6 @@ func _current_account_generation() -> int:
|
||||
return -1
|
||||
|
||||
func _cancel_account_bound_requests() -> void:
|
||||
if is_instance_valid(_catalogRequest):
|
||||
_catalogRequest.cancel_request()
|
||||
if is_instance_valid(_purchaseRequest):
|
||||
_purchaseRequest.cancel_request()
|
||||
_catalogRequestAccountGeneration = -1
|
||||
_purchaseRequestAccountGeneration = -1
|
||||
|
||||
@@ -926,14 +903,6 @@ func _reset_account_bound_state() -> void:
|
||||
_selectedItem = {}
|
||||
_hide_confirm_dialog()
|
||||
|
||||
func _auth_headers() -> PackedStringArray:
|
||||
var authManager := get_node_or_null("/root/AuthManager")
|
||||
var accessToken := str(authManager.call("get_access_token")).strip_edges() if authManager != null and authManager.has_method("get_access_token") else ""
|
||||
return PackedStringArray([
|
||||
"Content-Type: application/json",
|
||||
"Authorization: Bearer %s" % accessToken,
|
||||
])
|
||||
|
||||
func _submit_backend_purchase(item: Dictionary) -> void:
|
||||
var authManager := get_node_or_null("/root/AuthManager")
|
||||
var accessToken := str(authManager.call("get_access_token")).strip_edges() if authManager != null else ""
|
||||
@@ -949,43 +918,24 @@ func _submit_backend_purchase(item: Dictionary) -> void:
|
||||
"item_id": str(item.get("id", "")),
|
||||
}
|
||||
_purchaseRequestAccountGeneration = _current_account_generation()
|
||||
var err := _purchaseRequest.request("%s/shop/purchases" % NetworkConfig.get_api_base_url(), _auth_headers(), HTTPClient.METHOD_POST, JSON.stringify(payload))
|
||||
if err != OK:
|
||||
var api_client := get_node_or_null("/root/ApiClient")
|
||||
if api_client == null or not api_client.has_method("post_json"):
|
||||
_purchaseRequestAccountGeneration = -1
|
||||
_hide_confirm_dialog()
|
||||
_emit_event(EventNames.MALL_PURCHASE_FAILED, {"item": item, "reason": "request_failed"})
|
||||
_show_toast("购买请求发送失败")
|
||||
_show_toast("购买服务不可用")
|
||||
_update_purchase_button(_selectedItem)
|
||||
return
|
||||
api_client.call("post_json", "/shop/purchases", payload, _on_purchase_request_completed, true)
|
||||
|
||||
func _on_purchase_request_completed(result: int, responseCode: int, _headers: PackedStringArray, body: PackedByteArray) -> void:
|
||||
func _on_purchase_request_completed(success: bool, response: Dictionary, error_info: Dictionary) -> void:
|
||||
if _purchaseRequestAccountGeneration != _current_account_generation():
|
||||
return
|
||||
_purchaseRequestAccountGeneration = -1
|
||||
if result != HTTPRequest.RESULT_SUCCESS:
|
||||
_hide_confirm_dialog()
|
||||
_emit_event(EventNames.MALL_PURCHASE_FAILED, {"item": _selectedItem, "reason": "network_failed"})
|
||||
_show_toast("购买失败,请稍后再试")
|
||||
_update_purchase_button(_selectedItem)
|
||||
return
|
||||
var json := JSON.new()
|
||||
if json.parse(body.get_string_from_utf8()) != OK:
|
||||
_hide_confirm_dialog()
|
||||
_emit_event(EventNames.MALL_PURCHASE_FAILED, {"item": _selectedItem, "reason": "invalid_response"})
|
||||
_show_toast("购买响应解析失败")
|
||||
_update_purchase_button(_selectedItem)
|
||||
return
|
||||
var responseVariant: Variant = json.data
|
||||
if not (responseVariant is Dictionary):
|
||||
_hide_confirm_dialog()
|
||||
_emit_event(EventNames.MALL_PURCHASE_FAILED, {"item": _selectedItem, "reason": "invalid_response"})
|
||||
_show_toast("购买响应格式错误")
|
||||
_update_purchase_button(_selectedItem)
|
||||
return
|
||||
var response: Dictionary = responseVariant
|
||||
if responseCode < 200 or responseCode >= 300 or not bool(response.get("success", true)):
|
||||
if not success:
|
||||
_hide_confirm_dialog()
|
||||
_emit_event(EventNames.MALL_PURCHASE_FAILED, {"item": _selectedItem, "reason": "backend_rejected"})
|
||||
_show_toast(str(response.get("message", "购买失败")))
|
||||
_show_toast(str(error_info.get("message", "购买失败")))
|
||||
_update_purchase_button(_selectedItem)
|
||||
return
|
||||
var dataVariant: Variant = response.get("data", {})
|
||||
@@ -1030,37 +980,19 @@ func _fetch_catalog() -> void:
|
||||
_walletError = ""
|
||||
_update_currency()
|
||||
_catalogRequestAccountGeneration = _current_account_generation()
|
||||
var err := _catalogRequest.request("%s/shop/catalog" % NetworkConfig.get_api_base_url(), _auth_headers(), HTTPClient.METHOD_GET, "")
|
||||
if err != OK:
|
||||
var api_client := get_node_or_null("/root/ApiClient")
|
||||
if api_client == null or not api_client.has_method("get_json"):
|
||||
_catalogRequestAccountGeneration = -1
|
||||
_catalogLoading = false
|
||||
_catalogLoaded = false
|
||||
_catalogError = "商城数据请求发送失败"
|
||||
_walletLoading = false
|
||||
_walletLoaded = false
|
||||
_walletError = _catalogError
|
||||
_update_currency()
|
||||
_render_grid([])
|
||||
push_warning("MallPanel: 商城数据请求发送失败: %s" % error_string(err))
|
||||
_apply_catalog_error("商城服务不可用")
|
||||
return
|
||||
api_client.call("get_json", "/shop/catalog", _on_catalog_request_completed, true)
|
||||
|
||||
func _on_catalog_request_completed(result: int, responseCode: int, _headers: PackedStringArray, body: PackedByteArray) -> void:
|
||||
func _on_catalog_request_completed(success: bool, response: Dictionary, error_info: Dictionary) -> void:
|
||||
if _catalogRequestAccountGeneration != _current_account_generation():
|
||||
return
|
||||
_catalogRequestAccountGeneration = -1
|
||||
if result != HTTPRequest.RESULT_SUCCESS or responseCode < 200 or responseCode >= 300:
|
||||
_apply_catalog_error("商城数据读取失败")
|
||||
return
|
||||
var json := JSON.new()
|
||||
if json.parse(body.get_string_from_utf8()) != OK:
|
||||
_apply_catalog_error("商城响应解析失败")
|
||||
return
|
||||
var responseVariant: Variant = json.data
|
||||
if not (responseVariant is Dictionary):
|
||||
_apply_catalog_error("商城响应格式错误")
|
||||
return
|
||||
var response: Dictionary = responseVariant
|
||||
if not bool(response.get("success", true)):
|
||||
_apply_catalog_error(str(response.get("message", "商城数据读取失败")))
|
||||
if not success:
|
||||
_apply_catalog_error(str(error_info.get("message", "商城数据读取失败")))
|
||||
return
|
||||
var dataVariant: Variant = response.get("data", {})
|
||||
if not (dataVariant is Dictionary):
|
||||
|
||||
Reference in New Issue
Block a user