diff --git a/demo/.gitignore b/demo/.gitignore index 7de8ea5..546c011 100644 --- a/demo/.gitignore +++ b/demo/.gitignore @@ -1,3 +1,6 @@ # Godot 4+ specific ignores .godot/ android/ + +addons/godotopenxrvendors/ +local.gd diff --git a/demo/README.md b/demo/README.md new file mode 100644 index 0000000..c86d4a3 --- /dev/null +++ b/demo/README.md @@ -0,0 +1,12 @@ +# Godot Meta Toolkit Demo + +> Note: this project requires Godot 4.3 or later + +This is a demo project demonstrating usage of the Meta Platform SDK in a Godot project. Features of the Platform SDK showcased include: + +- Achievements (simple, count, and bitfield) +- Downloadable content +- Displaying bidirectional followers that also own the app +- Displaying user's name, profile image, and entitlement status + +For more info on using the Platform SDK, see [Getting Started with the Meta Platform SDK](https://godot-sdk-integrations.github.io/godot-meta-toolkit/manual/platform_sdk/getting_started.html) in the official docs. diff --git a/demo/assets/gltf/turkey.glb b/demo/assets/gltf/turkey.glb deleted file mode 100644 index a3bef62..0000000 Binary files a/demo/assets/gltf/turkey.glb and /dev/null differ diff --git a/demo/assets/gltf/turkey.glb.import b/demo/assets/gltf/turkey.glb.import deleted file mode 100644 index 9b9c3a0..0000000 --- a/demo/assets/gltf/turkey.glb.import +++ /dev/null @@ -1,38 +0,0 @@ -[remap] - -importer="scene" -importer_version=1 -type="PackedScene" -uid="uid://b8a73fckkvdxx" -path="res://.godot/imported/turkey.glb-1d18e191321082a17947d1ba7a072950.scn" - -[deps] - -source_file="res://assets/gltf/turkey.glb" -dest_files=["res://.godot/imported/turkey.glb-1d18e191321082a17947d1ba7a072950.scn"] - -[params] - -nodes/root_type="" -nodes/root_name="" -nodes/apply_root_scale=true -nodes/root_scale=1.0 -nodes/import_as_skeleton_bones=false -meshes/ensure_tangents=true -meshes/generate_lods=true -meshes/create_shadow_meshes=true -meshes/light_baking=1 -meshes/lightmap_texel_size=0.2 -meshes/force_disable_compression=false -skins/use_named_skins=true -animation/import=true -animation/fps=30 -animation/trimming=false -animation/remove_immutable_tracks=true -import_script/path="" -_subresources={} -fbx/importer=0 -fbx/allow_geometry_helper_nodes=false -fbx/embedded_image_handling=1 -gltf/naming_version=1 -gltf/embedded_image_handling=1 diff --git a/demo/export_presets.cfg b/demo/export_presets.cfg index 00c9f2d..88f7d1d 100644 --- a/demo/export_presets.cfg +++ b/demo/export_presets.cfg @@ -31,10 +31,10 @@ architectures/armeabi-v7a=false architectures/arm64-v8a=true architectures/x86=false architectures/x86_64=false -version/code=1 +version/code=10 version/name="" -package/unique_name="com.meta.w4.godot.toolkit.demo" -package/name="" +package/unique_name="com.w4.godot.toolkit.demo" +package/name="Godot Meta Toolkit Demo" package/signed=true package/app_category=2 package/retain_data_on_uninstall=false @@ -124,7 +124,7 @@ permissions/install_location_provider=false permissions/install_packages=false permissions/install_shortcut=false permissions/internal_system_window=false -permissions/internet=false +permissions/internet=true permissions/kill_background_processes=false permissions/location_hardware=false permissions/manage_accounts=false @@ -139,6 +139,7 @@ permissions/mount_format_filesystems=false permissions/mount_unmount_filesystems=false permissions/nfc=false permissions/persistent_activity=false +permissions/post_notifications=false permissions/process_outgoing_calls=false permissions/read_calendar=false permissions/read_call_log=false @@ -220,7 +221,19 @@ meta_xr_features/use_overlay_keyboard=false meta_xr_features/use_experimental_features=false meta_xr_features/boundary_mode=2 meta_xr_features/quest_1_support=false -meta_xr_features/quest_2_support=false +meta_xr_features/quest_2_support=true meta_xr_features/quest_3_support=true meta_xr_features/quest_pro_support=true xr_features/enable_pico_plugin=false +khronos_xr_features/vendors=0 +khronos_xr_features/htc/hand_tracking=0 +khronos_xr_features/htc/tracker=0 +khronos_xr_features/htc/eye_tracking=0 +khronos_xr_features/htc/lip_expression=0 +meta_xr_features/body_tracking=0 +meta_xr_features/use_anchor_sharing=false +pico_xr_features/eye_tracking=0 +pico_xr_features/face_tracking=0 +pico_xr_features/hand_tracking=0 +xr_features/enable_magicleap_plugin=false +magicleap_xr_features/hand_tracking=0 diff --git a/demo/icon.svg.import b/demo/icon.svg.import index a223e41..d2618ce 100644 --- a/demo/icon.svg.import +++ b/demo/icon.svg.import @@ -3,25 +3,27 @@ importer="texture" type="CompressedTexture2D" uid="uid://cmm67scocnrpg" -path="res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex" +path.s3tc="res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.s3tc.ctex" +path.etc2="res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.etc2.ctex" metadata={ -"vram_texture": false +"imported_formats": ["s3tc_bptc", "etc2_astc"], +"vram_texture": true } [deps] source_file="res://icon.svg" -dest_files=["res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex"] +dest_files=["res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.s3tc.ctex", "res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.etc2.ctex"] [params] -compress/mode=0 +compress/mode=2 compress/high_quality=false compress/lossy_quality=0.7 compress/hdr_compression=1 compress/normal_map=0 compress/channel_pack=0 -mipmaps/generate=false +mipmaps/generate=true mipmaps/limit=-1 roughness/mode=0 roughness/src_normal="" @@ -31,7 +33,7 @@ process/normal_map_invert_y=false process/hdr_as_srgb=false process/hdr_clamp_exposure=false process/size_limit=0 -detect_3d/compress_to=1 -svg/scale=1.0 +detect_3d/compress_to=0 +svg/scale=2.0 editor/scale_with_editor_scale=false editor/convert_colors_with_editor_theme=false diff --git a/demo/main.gd b/demo/main.gd index f8174cf..72ab04d 100644 --- a/demo/main.gd +++ b/demo/main.gd @@ -1,46 +1,359 @@ extends XROrigin3D -## Current XR interface -var xr_interface: XRInterface -var hand_tracking_source: Array[OpenXRInterface.HandTrackedSource] +const MAX_DISPLAY_FRIENDS := 5 +const PRODUCT_SKU := "00" +const SIMPLE_ACHIEVEMENT_NAME := "simple-achievement-example" +const COUNT_ACHIEVEMENT_NAME := "count-achievement-example" +const BITFIELD_ACHIEVEMENT_NAME := "bitfield-achievement-example" +const BITFIELD_ACHIEVEMENT_LENGTH := 5 -@onready var turkey = $turkey -@onready var left_controller_model: OpenXRFbRenderModel = $LeftController/LeftControllerRenderModel -@onready var right_controller_model: OpenXRFbRenderModel = $RightController/RightControllerRenderModel +# You need to supply your own application ID from https://developers.meta.com/ in order to test this app. +var APPLICATION_ID = "" + +var platform_sdk_initialized := false + +var purchase_processing := false +var product_purchased := false + +var simple_achievement_processing := true +var count_achievement_processing := true +var bitfield_achievement_processing := true +var simple_achievement_unlocked := false +var count_achievement_unlocked := false +var bitfield_achievement_unlocked := false + + +@onready var initialization_info: Node3D = $InitializationInfo +@onready var user_info: Node3D = $UserInfo +@onready var achievement_info: Node3D = $AchievementInfo +@onready var iap_info: Node3D = $IAPInfo +@onready var friend_info: Node3D = $FriendInfo + +@onready var left_controller_ray_cast: RayCast3D = $LeftController/LeftControllerRayCast +@onready var right_controller_ray_cast: RayCast3D = $RightController/RightControllerRayCast +@onready var initialization_label: Label3D = $InitializationInfo/InitializationLabel +@onready var entitled_label: Label3D = $UserInfo/EntitledLabel +@onready var oculus_id_label: Label3D = $UserInfo/OculusIDLabel +@onready var user_image: Sprite3D = $UserInfo/UserImage +@onready var friend_names_label: Label3D = $FriendInfo/FriendNamesLabel +@onready var iap_label: Label3D = $IAPInfo/IAPLabel +@onready var simple_achievement_label: Label3D = $AchievementInfo/SimpleAchievementInfo/SimpleAchievementLabel +@onready var count_achievement_label: Label3D = $AchievementInfo/CountAchievementInfo/CountAchievementLabel +@onready var bitfield_achievement_label: Label3D = $AchievementInfo/BitfieldAchievementInfo/BitfieldAchievementLabel -# Called when the node enters the scene tree for the first time. func _ready() -> void: - xr_interface = XRServer.find_interface("OpenXR") + var xr_interface = XRServer.find_interface("OpenXR") if xr_interface and xr_interface.is_initialized(): var vp: Viewport = get_viewport() vp.use_xr = true - # Give the viewport a 'transparent_bg' so we can see our passthrough vp.transparent_bg = true - - # Disable vsync DisplayServer.window_set_vsync_mode(DisplayServer.VSYNC_DISABLED) - - # Enable passthrough xr_interface.environment_blend_mode = XRInterface.XR_ENV_BLEND_MODE_ALPHA_BLEND - hand_tracking_source.resize(OpenXRInterface.HAND_MAX) - for hand in OpenXRInterface.HAND_MAX: - hand_tracking_source[hand] = xr_interface.get_hand_tracking_source(hand) + if ResourceLoader.exists("res://local.gd"): + var local = load('res://local.gd') + if local and "APPLICATION_ID" in local: + APPLICATION_ID = local.APPLICATION_ID + + if APPLICATION_ID == "": + initialization_label.text += "No app ID provided!" + hide_non_initialization_info() + return + + initialize_platform_sdk() + + +func initialize_platform_sdk(): + var result: MetaPlatformSDK_Message + + result = await MetaPlatformSDK.initialize_platform_async(APPLICATION_ID).completed + if result.is_error(): + initialization_label.text += "FAILED" + hide_non_initialization_info() + return + + var platform_initialize := result.get_platform_initialize() + if platform_initialize.result != MetaPlatformSDK.PLATFORM_INITIALIZE_SUCCESS: + initialization_label.text += "FAILED" + hide_non_initialization_info() + return + + platform_sdk_initialized = true + initialization_label.text += "SUCCESS" + + update_user_info() + update_friend_info() + update_iap_info() + update_achievement_info() + + +func update_user_info(): + var result: MetaPlatformSDK_Message + + result = await MetaPlatformSDK.entitlement_get_is_viewer_entitled_async().completed + if result.is_success(): + entitled_label.text += "TRUE" + else: + entitled_label.text += "FALSE" + + result = await MetaPlatformSDK.user_get_logged_in_user_async().completed + if result.is_error(): + oculus_id_label.text = "Failed to get user data!" + push_error("Failed to get user data: ", result.error) + return + + var user: MetaPlatformSDK_User = result.get_user() + oculus_id_label.text += user.oculus_id + + var image_request = HTTPRequest.new() + add_child(image_request) + image_request.request_completed.connect(self._image_request_completed.bind(image_request)) + + var error = image_request.request(user.image_url) + if error != OK: + push_error("There was an error with the image request.") + + +func update_friend_info(): + var result: MetaPlatformSDK_Message = await MetaPlatformSDK.user_get_logged_in_user_friends_async().completed + if result.is_error(): + friend_names_label.text = "Error retrieving friends!" + push_error("Error retrieving friends: ", result.error) + return + + + var friend_array := result.get_user_array() + if friend_array.size() == 0: + return + + var friend_count = 0 + friend_names_label.text = "" + for friend in friend_array: + if friend_count >= MAX_DISPLAY_FRIENDS: + break + var friend_name = friend.display_name if friend.display_name != "" else friend.oculus_id + friend_names_label.text += friend_name + "\n" + friend_count += 1 + + +func update_iap_info(): + var result: MetaPlatformSDK_Message = await MetaPlatformSDK.iap_get_viewer_purchases_async().completed + if result.is_error(): + iap_label.text = "Error getting\nuser purchases!" + purchase_processing = false + return + + var purchase_array := result.get_purchase_array() + for purchase: MetaPlatformSDK_Purchase in purchase_array: + if purchase.sku == PRODUCT_SKU: + product_purchased = true + break + + if product_purchased: + iap_label.text = "You have purchased\nthe in-app product!" + + purchase_processing = false + +func update_achievement_info(): + var result: MetaPlatformSDK_Message + result = await MetaPlatformSDK.achievements_get_all_progress_async().completed + if result.is_error(): + simple_achievement_label.text = "Error getting\nachievement progress!" + count_achievement_label.text = "Error getting\nachievement progress!" + bitfield_achievement_label.text = "Error getting\nachievement progress!" + simple_achievement_processing = false + count_achievement_processing = false + bitfield_achievement_processing = false + push_error("Couldn't get achievement progress: ", result.error) + return + + var achievement_progress_array := result.get_achievement_progress_array() + for achievement_progress: MetaPlatformSDK_AchievementProgress in achievement_progress_array: + match achievement_progress.name: + SIMPLE_ACHIEVEMENT_NAME: + if achievement_progress.is_unlocked: + simple_achievement_label.text = "Simple Achievement\nUnlocked!" + simple_achievement_unlocked = true + COUNT_ACHIEVEMENT_NAME: + if achievement_progress.is_unlocked: + count_achievement_label.text = "Count Achievement\nUnlocked!" + count_achievement_unlocked = true + else: + count_achievement_label.text = "Count is %s\nout of 3" % achievement_progress.count + BITFIELD_ACHIEVEMENT_NAME: + if achievement_progress.is_unlocked: + bitfield_achievement_label.text = "Bitfield Achievement\nUnlocked!" + bitfield_achievement_unlocked = true + else: + var active_bits = achievement_progress.bitfield.split().count("1") + bitfield_achievement_label.text = "%s of 5 bits active\nActivate 3 bits to unlock" % active_bits + + simple_achievement_processing = false + count_achievement_processing = false + bitfield_achievement_processing = false + + +func hide_non_initialization_info(): + user_info.hide() + achievement_info.hide() + iap_info.hide() + friend_info.hide() + + +func update(collider_name): + if not platform_sdk_initialized: + return + + match collider_name: + "IAPButton": + purchase_product() + "SimpleAchievementButton": + unlock_simple_achievement() + "CountAchievementButton": + increment_count_achievement() + "BitfieldAchievementButton1": + add_field_bitfield_achievement(0) + "BitfieldAchievementButton2": + add_field_bitfield_achievement(1) + "BitfieldAchievementButton3": + add_field_bitfield_achievement(2) + "BitfieldAchievementButton4": + add_field_bitfield_achievement(3) + "BitfieldAchievementButton5": + add_field_bitfield_achievement(4) + + +func purchase_product(): + if purchase_processing or product_purchased: + return + + iap_label.text = "Processing..." + purchase_processing = true + + # This App's example product is listed as free in the Meta Quest Developer Dashboard. + # Launching checkout flow for a free product like this will cause a panel to appear momentarily. + var result: MetaPlatformSDK_Message = await MetaPlatformSDK.iap_launch_checkout_flow_async(PRODUCT_SKU).completed + if result.is_error(): + iap_label.text = "Error launching\nproduct checkout flow!" + purchase_processing = false; + return + + update_iap_info() + + +func unlock_simple_achievement(): + if simple_achievement_processing or simple_achievement_unlocked: + return + + simple_achievement_label.text = "Processing..." + simple_achievement_processing = true + + var result: MetaPlatformSDK_Message = await MetaPlatformSDK.achievements_unlock_async(SIMPLE_ACHIEVEMENT_NAME).completed + if result.is_error(): + simple_achievement_label.text = "Error unlocking\nSimple Achievement" + else: + var achievement_update := result.get_achievement_update() + if achievement_update.just_unlocked: + simple_achievement_label.text = "Simple Achievement\njust unlocked!" + simple_achievement_unlocked = true + + simple_achievement_processing = false + + +func increment_count_achievement(): + if count_achievement_processing or count_achievement_unlocked: + return + + count_achievement_label.text = "Processing..." + count_achievement_processing = true + + var result: MetaPlatformSDK_Message = await MetaPlatformSDK.achievements_add_count_async(COUNT_ACHIEVEMENT_NAME, 1).completed + if result.is_error(): + count_achievement_label.text = "Error adding to\nCount Achievement" + else: + var achievement_update := result.get_achievement_update() + if achievement_update.just_unlocked: + count_achievement_label.text = "Count Achievement\njust unlocked!" + count_achievement_unlocked = true + else: + update_count_achievement_progress() + + count_achievement_processing = false + + +func update_count_achievement_progress(): + var result: MetaPlatformSDK_Message = await MetaPlatformSDK.achievements_get_progress_by_name_async([COUNT_ACHIEVEMENT_NAME]).completed + if result.is_error(): + count_achievement_label.text = "Error checking\nCount Achievement progress" + else: + var achievement_progress_array := result.get_achievement_progress_array() + for achievement_progress: MetaPlatformSDK_AchievementProgress in achievement_progress_array: + if achievement_progress.name != COUNT_ACHIEVEMENT_NAME: + continue + count_achievement_label.text = "Count is %s\nout of 3" % achievement_progress.count + return + + +func add_field_bitfield_achievement(bitfield_position: int): + if bitfield_achievement_processing or bitfield_achievement_unlocked: + return + + bitfield_achievement_label.text = "Processing..." + bitfield_achievement_processing = true + + var bitfield := "" + for i in BITFIELD_ACHIEVEMENT_LENGTH: + bitfield += "1" if i == bitfield_position else "0" + + var result: MetaPlatformSDK_Message = await MetaPlatformSDK.achievements_add_fields_async(BITFIELD_ACHIEVEMENT_NAME, bitfield).completed + if result.is_error(): + bitfield_achievement_label.text = "Error adding field to\nBitfield Achievement" + else: + var achievement_update := result.get_achievement_update() + if achievement_update.just_unlocked: + bitfield_achievement_label.text = "Bitfield Achievement\njust unlocked!" + bitfield_achievement_unlocked = true + else: + update_bitfield_achievement_progress() + + bitfield_achievement_processing = false + + +func update_bitfield_achievement_progress(): + var result: MetaPlatformSDK_Message = await MetaPlatformSDK.achievements_get_progress_by_name_async([BITFIELD_ACHIEVEMENT_NAME]).completed + if result.is_error(): + bitfield_achievement_label.text = "Error checking\nBitfield Achievement progress" + else: + var achievement_progress_array := result.get_achievement_progress_array() + for achievement_progress: MetaPlatformSDK_AchievementProgress in achievement_progress_array: + if achievement_progress.name != BITFIELD_ACHIEVEMENT_NAME: + continue + var active_bits = achievement_progress.bitfield.split().count("1") + bitfield_achievement_label.text = "%s of 5 bits active\nActivate 3 bits to unlock" % active_bits + return + + +func _on_left_controller_button_pressed(name: String) -> void: + if name == "trigger_click" and left_controller_ray_cast.is_colliding(): + var collider = left_controller_ray_cast.get_collider() + update(collider.name) -# Called every frame. 'delta' is the elapsed time since the previous frame. -func _physics_process(delta: float) -> void: - # Make the gltf model slowly rotate - if turkey: - turkey.rotate_y(0.001) - for hand in OpenXRInterface.HAND_MAX: - var source = xr_interface.get_hand_tracking_source(hand) - if hand_tracking_source[hand] == source: - continue +func _on_right_controller_button_pressed(name: String) -> void: + if name == "trigger_click" and right_controller_ray_cast.is_colliding(): + var collider = right_controller_ray_cast.get_collider() + update(collider.name) - var controller = left_controller_model if (hand == OpenXRInterface.HAND_LEFT) else right_controller_model - controller.visible = (source == OpenXRInterface.HAND_TRACKED_SOURCE_CONTROLLER) - hand_tracking_source[hand] = source +func _image_request_completed(_result: int, response_code: int, headers: PackedStringArray, body: PackedByteArray, image_request: HTTPRequest): + if response_code != 200 or not headers.has("Content-Type: image/png"): + push_error("Image request was not successful.") + image_request.queue_free() + return + var image = Image.new() + image.load_png_from_buffer(body) + var image_texture = ImageTexture.create_from_image(image) + user_image.texture = image_texture + image_request.queue_free() diff --git a/demo/main.tscn b/demo/main.tscn index d27712d..0b3352d 100644 --- a/demo/main.tscn +++ b/demo/main.tscn @@ -1,7 +1,8 @@ -[gd_scene load_steps=6 format=3 uid="uid://c0ol8en13wpk3"] +[gd_scene load_steps=17 format=3 uid="uid://c0ol8en13wpk3"] [ext_resource type="Script" path="res://main.gd" id="1_t3hrc"] -[ext_resource type="PackedScene" uid="uid://b8a73fckkvdxx" path="res://assets/gltf/turkey.glb" id="2_lrsmu"] +[ext_resource type="Script" path="res://raycast.gd" id="2_5nsls"] +[ext_resource type="Texture2D" uid="uid://cmm67scocnrpg" path="res://icon.svg" id="3_qj576"] [sub_resource type="ProceduralSkyMaterial" id="ProceduralSkyMaterial_h1cjv"] sky_horizon_color = Color(0.64625, 0.65575, 0.67075, 1) @@ -14,6 +15,38 @@ sky_material = SubResource("ProceduralSkyMaterial_h1cjv") sky = SubResource("Sky_a1pyg") tonemap_mode = 2 +[sub_resource type="CylinderMesh" id="CylinderMesh_75bh1"] +top_radius = 0.005 +bottom_radius = 0.005 + +[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_vpekr"] +shading_mode = 0 + +[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_mguh3"] +shading_mode = 0 + +[sub_resource type="BoxShape3D" id="BoxShape3D_me425"] +size = Vector3(0.745117, 0.297852, 0.102539) + +[sub_resource type="BoxMesh" id="BoxMesh_14q82"] +size = Vector3(0.745, 0.3, 0.1) + +[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_ck6b4"] +shading_mode = 0 +albedo_color = Color(1, 0, 0, 1) + +[sub_resource type="BoxShape3D" id="BoxShape3D_r6q7v"] +size = Vector3(0.308594, 0.297852, 0.102539) + +[sub_resource type="BoxMesh" id="BoxMesh_dy7is"] +size = Vector3(0.3, 0.3, 0.1) + +[sub_resource type="BoxShape3D" id="BoxShape3D_yn5xr"] +size = Vector3(1.44531, 0.297852, 0.102539) + +[sub_resource type="BoxMesh" id="BoxMesh_7ncv3"] +size = Vector3(1.445, 0.3, 0.1) + [node name="Main" type="XROrigin3D"] script = ExtResource("1_t3hrc") @@ -28,29 +61,224 @@ transform = Transform3D(-0.866025, -0.433013, 0.25, -0.12941, -0.288849, -0.9485 [node name="XRCamera3D" type="XRCamera3D" parent="."] -[node name="turkey" parent="." instance=ExtResource("2_lrsmu")] -transform = Transform3D(0.7, 0, 0, 0, 0.7, 0, 0, 0, 0.7, 0, 0.5, -0.7) - [node name="LeftController" type="XRController3D" parent="."] tracker = &"left_hand" pose = &"grip" -[node name="LeftControllerRenderModel" type="OpenXRFbRenderModel" parent="LeftController"] +[node name="LeftControllerRayCast" type="RayCast3D" parent="LeftController"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -0.059, -0.052) +target_position = Vector3(0, -10, 0) +script = ExtResource("2_5nsls") + +[node name="MeshInstance3D" type="MeshInstance3D" parent="LeftController/LeftControllerRayCast"] +mesh = SubResource("CylinderMesh_75bh1") +surface_material_override/0 = SubResource("StandardMaterial3D_vpekr") [node name="RightController" type="XRController3D" parent="."] tracker = &"right_hand" pose = &"grip" -[node name="RightControllerRenderModel" type="OpenXRFbRenderModel" parent="RightController"] -render_model_type = 1 +[node name="RightControllerRayCast" type="RayCast3D" parent="RightController"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -0.059, -0.052) +target_position = Vector3(0, -10, 0) +script = ExtResource("2_5nsls") + +[node name="MeshInstance3D" type="MeshInstance3D" parent="RightController/RightControllerRayCast"] +mesh = SubResource("CylinderMesh_75bh1") +surface_material_override/0 = SubResource("StandardMaterial3D_mguh3") + +[node name="InitializationInfo" type="Node3D" parent="."] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.831041, -3) + +[node name="InitializationLabel" type="Label3D" parent="InitializationInfo"] +text = "SDK Initialization: " + +[node name="UserInfo" type="Node3D" parent="."] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.48694, -3) +metadata/_edit_group_ = true + +[node name="UserImage" type="Sprite3D" parent="UserInfo"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.450442, 0) +pixel_size = 0.002 +texture = ExtResource("3_qj576") + +[node name="OculusIDLabel" type="Label3D" parent="UserInfo"] +text = "User Oculus ID: " + +[node name="EntitledLabel" type="Label3D" parent="UserInfo"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -0.224751, 0) +text = "User Entitled: " + +[node name="AchievementInfo" type="Node3D" parent="."] +transform = Transform3D(0.866025, 0, 0.5, 0, 1, 0, -0.5, 0, 0.866025, -2.11312, 1, -2.52491) +metadata/_edit_group_ = true + +[node name="SimpleAchievementInfo" type="Node3D" parent="AchievementInfo"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.15314, 0) + +[node name="SimpleAchievementLabel" type="Label3D" parent="AchievementInfo/SimpleAchievementInfo"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.199842, 0) +text = "Press Button +to Unlock +Simple Achievement" + +[node name="SimpleAchievementButton" type="StaticBody3D" parent="AchievementInfo/SimpleAchievementInfo"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -0.297091, 0) +metadata/_edit_group_ = true + +[node name="CollisionShape3D" type="CollisionShape3D" parent="AchievementInfo/SimpleAchievementInfo/SimpleAchievementButton"] +shape = SubResource("BoxShape3D_me425") + +[node name="MeshInstance3D" type="MeshInstance3D" parent="AchievementInfo/SimpleAchievementInfo/SimpleAchievementButton"] +mesh = SubResource("BoxMesh_14q82") +surface_material_override/0 = SubResource("StandardMaterial3D_ck6b4") + +[node name="Label3D" type="Label3D" parent="AchievementInfo/SimpleAchievementInfo/SimpleAchievementButton"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0.0689178) +text = "Unlock" + +[node name="CountAchievementInfo" type="Node3D" parent="AchievementInfo"] + +[node name="CountAchievementLabel" type="Label3D" parent="AchievementInfo/CountAchievementInfo"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.199842, 0) +text = "Press Button Three +Times to Unlock +Count Achievement" + +[node name="CountAchievementButton" type="StaticBody3D" parent="AchievementInfo/CountAchievementInfo"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -0.297091, 0) +metadata/_edit_group_ = true + +[node name="CollisionShape3D" type="CollisionShape3D" parent="AchievementInfo/CountAchievementInfo/CountAchievementButton"] +shape = SubResource("BoxShape3D_me425") + +[node name="MeshInstance3D" type="MeshInstance3D" parent="AchievementInfo/CountAchievementInfo/CountAchievementButton"] +mesh = SubResource("BoxMesh_14q82") +surface_material_override/0 = SubResource("StandardMaterial3D_ck6b4") + +[node name="Label3D" type="Label3D" parent="AchievementInfo/CountAchievementInfo/CountAchievementButton"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0.0689178) +text = "Unlock" + +[node name="BitfieldAchievementInfo" type="Node3D" parent="AchievementInfo"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -1.1892, 0) + +[node name="BitfieldAchievementLabel" type="Label3D" parent="AchievementInfo/BitfieldAchievementInfo"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.199842, 0) +text = "Press Three of Five +Buttons to Unlock +Bitfield Achievement" + +[node name="BitfieldAchievementButton1" type="StaticBody3D" parent="AchievementInfo/BitfieldAchievementInfo"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.7, -0.297, 0) +metadata/_edit_group_ = true + +[node name="CollisionShape3D" type="CollisionShape3D" parent="AchievementInfo/BitfieldAchievementInfo/BitfieldAchievementButton1"] +shape = SubResource("BoxShape3D_r6q7v") + +[node name="MeshInstance3D" type="MeshInstance3D" parent="AchievementInfo/BitfieldAchievementInfo/BitfieldAchievementButton1"] +mesh = SubResource("BoxMesh_dy7is") +surface_material_override/0 = SubResource("StandardMaterial3D_ck6b4") + +[node name="Label3D" type="Label3D" parent="AchievementInfo/BitfieldAchievementInfo/BitfieldAchievementButton1"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0.0689178) +text = "1" + +[node name="BitfieldAchievementButton2" type="StaticBody3D" parent="AchievementInfo/BitfieldAchievementInfo"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.35, -0.297, 0) +metadata/_edit_group_ = true + +[node name="CollisionShape3D" type="CollisionShape3D" parent="AchievementInfo/BitfieldAchievementInfo/BitfieldAchievementButton2"] +shape = SubResource("BoxShape3D_r6q7v") + +[node name="MeshInstance3D" type="MeshInstance3D" parent="AchievementInfo/BitfieldAchievementInfo/BitfieldAchievementButton2"] +mesh = SubResource("BoxMesh_dy7is") +surface_material_override/0 = SubResource("StandardMaterial3D_ck6b4") + +[node name="Label3D" type="Label3D" parent="AchievementInfo/BitfieldAchievementInfo/BitfieldAchievementButton2"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0.0689178) +text = "2" + +[node name="BitfieldAchievementButton3" type="StaticBody3D" parent="AchievementInfo/BitfieldAchievementInfo"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -0.297091, 0) +metadata/_edit_group_ = true + +[node name="CollisionShape3D" type="CollisionShape3D" parent="AchievementInfo/BitfieldAchievementInfo/BitfieldAchievementButton3"] +shape = SubResource("BoxShape3D_r6q7v") + +[node name="MeshInstance3D" type="MeshInstance3D" parent="AchievementInfo/BitfieldAchievementInfo/BitfieldAchievementButton3"] +mesh = SubResource("BoxMesh_dy7is") +surface_material_override/0 = SubResource("StandardMaterial3D_ck6b4") + +[node name="Label3D" type="Label3D" parent="AchievementInfo/BitfieldAchievementInfo/BitfieldAchievementButton3"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0.0689178) +text = "3" + +[node name="BitfieldAchievementButton4" type="StaticBody3D" parent="AchievementInfo/BitfieldAchievementInfo"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.35, -0.297, 0) +metadata/_edit_group_ = true + +[node name="CollisionShape3D" type="CollisionShape3D" parent="AchievementInfo/BitfieldAchievementInfo/BitfieldAchievementButton4"] +shape = SubResource("BoxShape3D_r6q7v") + +[node name="MeshInstance3D" type="MeshInstance3D" parent="AchievementInfo/BitfieldAchievementInfo/BitfieldAchievementButton4"] +mesh = SubResource("BoxMesh_dy7is") +surface_material_override/0 = SubResource("StandardMaterial3D_ck6b4") + +[node name="Label3D" type="Label3D" parent="AchievementInfo/BitfieldAchievementInfo/BitfieldAchievementButton4"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0.0689178) +text = "4" + +[node name="BitfieldAchievementButton5" type="StaticBody3D" parent="AchievementInfo/BitfieldAchievementInfo"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.7, -0.297, 0) +metadata/_edit_group_ = true + +[node name="CollisionShape3D" type="CollisionShape3D" parent="AchievementInfo/BitfieldAchievementInfo/BitfieldAchievementButton5"] +shape = SubResource("BoxShape3D_r6q7v") + +[node name="MeshInstance3D" type="MeshInstance3D" parent="AchievementInfo/BitfieldAchievementInfo/BitfieldAchievementButton5"] +mesh = SubResource("BoxMesh_dy7is") +surface_material_override/0 = SubResource("StandardMaterial3D_ck6b4") + +[node name="Label3D" type="Label3D" parent="AchievementInfo/BitfieldAchievementInfo/BitfieldAchievementButton5"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0.0689178) +text = "5" + +[node name="IAPInfo" type="Node3D" parent="."] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, -3) +metadata/_edit_group_ = true + +[node name="IAPLabel" type="Label3D" parent="IAPInfo"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.199842, 0) +text = "Press the button below +to purchase in-app product" + +[node name="IAPButton" type="StaticBody3D" parent="IAPInfo"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -0.297091, 0) +metadata/_edit_group_ = true + +[node name="CollisionShape3D" type="CollisionShape3D" parent="IAPInfo/IAPButton"] +shape = SubResource("BoxShape3D_yn5xr") + +[node name="MeshInstance3D" type="MeshInstance3D" parent="IAPInfo/IAPButton"] +mesh = SubResource("BoxMesh_7ncv3") +surface_material_override/0 = SubResource("StandardMaterial3D_ck6b4") + +[node name="Label3D" type="Label3D" parent="IAPInfo/IAPButton"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0.0689178) +text = "Purchase Product" -[node name="LeftXRHandModifier3D" type="XRHandModifier3D" parent="."] +[node name="FriendInfo" type="Node3D" parent="."] +transform = Transform3D(0.707107, 0, -0.707107, 0, 1, 0, 0.707107, 0, 0.707107, 2.113, 1, -2.525) +metadata/_edit_group_ = true -[node name="LeftHandModel" type="OpenXRFbHandTrackingMesh" parent="LeftXRHandModifier3D"] +[node name="FriendsLabel" type="Label3D" parent="FriendInfo"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.493917, 0) +text = "Friends Who Own This App:" -[node name="RightXRHandModifier3D" type="XRHandModifier3D" parent="."] -hand_tracker = &"/user/right" +[node name="FriendNamesLabel" type="Label3D" parent="FriendInfo"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -0.347479, 0) +text = "None" -[node name="RightHandModel" type="OpenXRFbHandTrackingMesh" parent="RightXRHandModifier3D"] -hand = 1 -use_scale_override = false +[connection signal="button_pressed" from="LeftController" to="." method="_on_left_controller_button_pressed"] +[connection signal="button_pressed" from="RightController" to="." method="_on_right_controller_button_pressed"] diff --git a/demo/project.godot b/demo/project.godot index 228e5a1..8f2f29f 100644 --- a/demo/project.godot +++ b/demo/project.godot @@ -15,10 +15,6 @@ run/main_scene="res://main.tscn" config/features=PackedStringArray("4.3", "GL Compatibility") config/icon="res://icon.svg" -[debug] - -settings/stdout/verbose_stdout=true - [rendering] renderer/rendering_method="gl_compatibility" diff --git a/demo/raycast.gd b/demo/raycast.gd new file mode 100644 index 0000000..b0f4371 --- /dev/null +++ b/demo/raycast.gd @@ -0,0 +1,16 @@ +extends RayCast3D + +@onready var mesh_instance_3d: MeshInstance3D = $MeshInstance3D + +func _process(delta: float) -> void: + var mat = mesh_instance_3d.get_surface_override_material(0) + + if not is_colliding(): + mesh_instance_3d.mesh.height = 10 + mesh_instance_3d.position.y = -5 + mat.albedo_color = Color.RED + else: + var height = (get_collision_point() - global_position).length() + mesh_instance_3d.mesh.height = height + mesh_instance_3d.position.y = -(height / 2) + mat.albedo_color = Color.GREEN diff --git a/docs/manual/platform_sdk/getting_started.rst b/docs/manual/platform_sdk/getting_started.rst index 8ec3cf0..7be4340 100644 --- a/docs/manual/platform_sdk/getting_started.rst +++ b/docs/manual/platform_sdk/getting_started.rst @@ -58,4 +58,7 @@ After that process is complete, you'll be able to use the Platform SDK: for user in result.data: print("- ", user) +If you'd like to see more examples of using the Meta Platform SDK in a Godot project, be sure to check out the Godot Meta Toolkit Demo. +Source code for the project can be found on `GitHub `_. + For more information, see the API docs for the :ref:`MetaPlatformSDK` singleton. It's the entry point for doing anything with the Meta Platform SDK.