Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: fetch collectibles wearables from your address #300

Merged
merged 1 commit into from
Feb 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions godot/.godot/global_script_class_cache.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -108,12 +108,6 @@ list=Array[Dictionary]([{
"path": "res://src/ui/components/emotes/emotes.gd"
}, {
"base": &"RefCounted",
"class": &"EmotesRequest",
"icon": "",
"language": &"GDScript",
"path": "res://src/ui/components/emote_editor/emotes_request.gd"
}, {
"base": &"RefCounted",
"class": &"Erc20",
"icon": "",
"language": &"GDScript",
Expand Down Expand Up @@ -263,6 +257,12 @@ list=Array[Dictionary]([{
"language": &"GDScript",
"path": "res://src/ui/components/wearable_item/wearable_item.gd"
}, {
"base": &"RefCounted",
"class": &"WearableRequest",
"icon": "",
"language": &"GDScript",
"path": "res://src/decentraland_components/avatar/wearables/lambda_wearable_request.gd"
}, {
"base": &"Node",
"class": &"Wearables",
"icon": "",
Expand Down
32 changes: 16 additions & 16 deletions godot/assets/themes/theme.tres
kuruk-mm marked this conversation as resolved.
Show resolved Hide resolved

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ func async_play_emote(emote_urn: String) -> void:


func _async_load_emote(emote_urn: String):
await EmotesRequest.async_fetch_emote(emote_urn)
await WearableRequest.async_fetch_emote(emote_urn)

var emote_content_promises = async_fetch_emote(emote_urn, avatar.avatar_data.get_body_shape())
await PromiseUtils.async_all(emote_content_promises)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
class_name WearableRequest

const WEARABLE_PAGE_SIZE = 100


class LambdaWearableItemResponse:
var urn: String = ""
var token_id: String = ""
var transferet_at: int = 0
var wearable_name: String = ""
var wearable_category: String = ""
var wearable_rarity: String = ""

static func from_dictionary(dictionary: Dictionary) -> Array[LambdaWearableItemResponse]:
var response: Array[LambdaWearableItemResponse] = []
var individual_data = dictionary.get("individualData", [{}])
for data in individual_data:
var item = LambdaWearableItemResponse.new()
item.urn = data.get("id", "")
item.token_id = data.get("tokenId", "")
item.transferet_at = int(data.get("transferredAt", "0"))

item.wearable_name = dictionary.get("name", "")
item.wearable_category = dictionary.get("category", "")
item.wearable_rarity = dictionary.get("rarity", "")
response.push_back(item)
return response


class LambdaWearableResponse:
var elements: Array[LambdaWearableItemResponse]
var total_amount: int = 0

static func from_dictionary(dictionary: Dictionary) -> LambdaWearableResponse:
var response = LambdaWearableResponse.new()

var emotes = dictionary.get("elements", [])
for emote in emotes:
response.elements.append_array(LambdaWearableItemResponse.from_dictionary(emote))

response.total_amount = dictionary.get("totalAmount", 0)
return response


static func async_fetch_emote(emote_urn: String):
var emote_data_promises = Global.content_provider.fetch_wearables(
[emote_urn], Global.realm.get_profile_content_url()
)
await PromiseUtils.async_all(emote_data_promises)


static func _async_request(
url: String, page_number: int = 1, page_size: int = 10
) -> LambdaWearableResponse:
url += "?pageNum=%d" % page_number
url += "&pageSize=%d" % page_size

var promise: Promise = Global.http_requester.request_json(url, HTTPClient.METHOD_GET, "", [])

var result = await PromiseUtils.async_awaiter(promise)

if result is PromiseError:
printerr("Error request emotes: ", result.get_error())
return

var json: Dictionary = result.get_string_response_as_json()

return LambdaWearableResponse.from_dictionary(json)


static func async_request_emotes(
page_number: int = 1, page_size: int = 10
) -> LambdaWearableResponse:
var address = Global.player_identity.get_address_str()
if address.is_empty():
return

var url = Global.player_identity.current_lambda_server_base_url + "users/" + address + "/emotes"

return await _async_request(url, page_number, page_size)


static func async_request_all_wearables() -> LambdaWearableResponse:
var response: LambdaWearableResponse = LambdaWearableResponse.new()
var page_number = 1
while true:
var wearables = await async_request_wearables(page_number, WEARABLE_PAGE_SIZE)
if not is_instance_valid(wearables):
return null
response.total_amount = wearables.total_amount
response.elements.append_array(wearables.elements)
var loaded_elements = page_number * WEARABLE_PAGE_SIZE
if loaded_elements >= response.total_amount:
break
page_number += 1

return response


static func async_request_wearables(
page_number: int = 1, page_size: int = 10
) -> LambdaWearableResponse:
var address = Global.player_identity.get_address_str()
if address.is_empty():
return null

var url = (
Global.player_identity.current_lambda_server_base_url + "users/" + address + "/wearables"
)

return await _async_request(url, page_number, page_size)
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,7 @@ class ItemRarity:


class Categories:
const ALL: String = "all"
const EYES: String = "eyes"
const EYEBROWS: String = "eyebrows"
const MOUTH: String = "mouth"
Expand Down Expand Up @@ -402,6 +403,7 @@ class Categories:
FEET: [FEET],
HAT: [EARRING, EYEWEAR, HAT, HELMET, MASK, TIARA, TOP_HEAD], # accesories...
SKIN: [SKIN],
ALL: [ALL],
}

const ALL_CATEGORIES: PackedStringArray = [
Expand Down Expand Up @@ -439,6 +441,10 @@ static func is_texture(category: String) -> bool:
return false


static func is_base_wearable(wearable_name: String) -> bool:
return wearable_name.begins_with("urn:decentraland:off-chain:base-avatars:")


static func get_base_avatar_urn(wearable_name: String):
return "urn:decentraland:off-chain:base-avatars:" + wearable_name

Expand Down
43 changes: 32 additions & 11 deletions godot/src/ui/components/backpack/backpack.gd
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@ const FILTER: Texture = preload("res://assets/ui/Filter.svg")

@export var hide_navbar: bool = false

var wearable_button_group = ButtonGroup.new()
var wearable_button_group_per_category: Dictionary = {}
var filtered_data: Array
var current_filter: String = ""
var only_collectibles: bool = false

var base_wearable_request_id: int = -1
var wearable_data: Dictionary = {}
Expand Down Expand Up @@ -57,6 +59,11 @@ var _has_changes: bool = false

# gdlint:ignore = async-function-name
func _ready():
for category in Wearables.Categories.ALL_CATEGORIES:
var button_group = ButtonGroup.new()
button_group.allow_unpress = _can_unequip(category)
wearable_button_group_per_category[category] = button_group

if hide_navbar:
container_navbar.hide()

Expand Down Expand Up @@ -90,14 +97,21 @@ func _ready():
var key = Wearables.get_base_avatar_urn(wearable_id)
wearable_data[key] = null

# Load all remote wearables that you own...
var remote_wearables = await WearableRequest.async_request_all_wearables()
if remote_wearables != null:
for wearable_item in remote_wearables.elements:
wearable_data[wearable_item.urn] = null

var promise = Global.content_provider.fetch_wearables(
wearable_data.keys(), Global.realm.get_profile_content_url()
)
await PromiseUtils.async_all(promise)

for wearable_id in wearable_data:
wearable_data[wearable_id] = Global.content_provider.get_wearable(wearable_id)
if wearable_data[wearable_id] == null:
var wearable = Global.content_provider.get_wearable(wearable_id)
wearable_data[wearable_id] = wearable
if wearable == null:
printerr("Error loading wearable_id ", wearable_id)

_update_visible_categories()
Expand Down Expand Up @@ -182,14 +196,20 @@ func _load_filtered_data(filter: String):
return

filtered_data = []
current_filter = filter
for wearable_id in wearable_data:
var wearable = wearable_data[wearable_id]
if wearable != null:
if wearable.get_category() == filter:
if (
Wearables.can_equip(wearable, mutable_avatar.get_body_shape())
or wearable.get_category() == "body_shape"
):
var is_filter_all = filter == "all"
if wearable.get_category() == filter or is_filter_all:
var is_body_shape = wearable.get_category() == "body_shape"
var is_equipable = Wearables.can_equip(wearable, mutable_avatar.get_body_shape())
var is_base_wearable = Wearables.is_base_wearable(wearable_id)
var can_use = (
(is_equipable and (!is_base_wearable or !only_collectibles))
or (is_body_shape and !is_filter_all)
)
if can_use:
filtered_data.push_back(wearable_id)

request_show_wearables = true
Expand All @@ -214,8 +234,7 @@ func _show_wearables():
var wearable_item = WEARABLE_ITEM_INSTANTIABLE.instantiate()
var wearable = wearable_data[wearable_id]
grid_container_wearables_list.add_child(wearable_item)
wearable_button_group.allow_unpress = _can_unequip(wearable.get_category())
wearable_item.button_group = wearable_button_group
wearable_item.button_group = wearable_button_group_per_category.get(wearable.get_category())
wearable_item.async_set_wearable(wearable)

# Connect signals
Expand Down Expand Up @@ -360,7 +379,7 @@ func _on_wearable_unequip(wearable_id: String):
var category = desired_wearable.get_category()

if category == Wearables.Categories.BODY_SHAPE:
# TODO: can not unequip a body shape
# can not unequip a body shape
return

var new_avatar_wearables := mutable_avatar.get_wearables()
Expand Down Expand Up @@ -445,3 +464,5 @@ func _on_button_emotes_pressed():

func _on_check_box_only_collectibles_toggled(toggled_on):
emote_editor.async_set_only_collectibles(toggled_on)
only_collectibles = toggled_on
_load_filtered_data(current_filter)
Loading
Loading