Search Unity

Need help to understand how to use Photon with ARCore for Cloud Anchors instead of UNet

Discussion in 'AR' started by Omni_Owl, Mar 14, 2019.

  1. Omni_Owl

    Omni_Owl

    Joined:
    Nov 26, 2013
    Posts:
    176
    I'm really racking my brain here trying to understand how I should do this. I'm trying to do a multiplayer AR game, using ARCore with Cloud Anchors for my Master's Thesis.

    Using Photon 2, the flow is this:
    1. Master client makes a room.
    2. Master client starts looking for surfaces, using ARCore.
    3. Eventually Master Client has found some surfaces and will be placing an Anchor, to attach the Game Arena to.
    4. When this anchor is placed, Photon should show the Arena that is now spawned but consistently in AR across devices.
    5. The way to do this, as I understand it, is to share the initial Anchor used by the host.
    At least, that's how it is in my head.

    But I am hitting a snag here. I have never used Photon before so I am in doubt on what parts Photon should do and what parts I pass to Google (I already have some code that makes a room that multiple people can join).

    Their Cloud Anchor example is written with UNet and I can't quite figure out how to do the translation to Photon. Frankly I shouldn't use the UNet example either way as UNet is discontinued now.

    When my Pong Launcher makes the room, the following happens:

    ARPongLauncher.cs

    Code (CSharp):
    1. public override void OnJoinedRoom()
    2. {
    3.     if (IsDialogShown == true)
    4.     {
    5.         IsDialogShown = false;
    6.         DialogAnimator.SetBool("IsHidden", true);
    7.     }
    8.     SnackbarText.text = $"Successfully joined {PhotonNetwork.CurrentRoom.Name}";
    9.     LobbyScreen.SetActive(false);
    10.     TopBar.SetActive(true);
    11.  
    12.     PlayerCountText.text = $"{PhotonNetwork.PlayerList.Length}";
    13.     if (PhotonNetwork.LocalPlayer.IsMasterClient)
    14.     {
    15.         ARPongMasterClient masterClient = PlayerPrefab.AddComponent<ARPongMasterClient>();
    16.         masterClient.searchMessage = "Searching for Surfaces...";
    17.         masterClient.AnchorPrefabName = AnchorPrefabName;
    18.         masterClient.FirstPersonCamera = PlayerPrefab.GetComponentInChildren<Camera>();
    19.         masterClient.SnackbarText = SnackbarText;
    20.         masterClient.m_ARCoreWorldOriginHelper = PlayerPrefab.GetComponentInChildren<ARCoreWorldOriginHelper>();
    21.         masterClient.OnAnchorHosted += Handle_OnAnchorHosted;
    22.     }
    23. }
    Then in the client I do this:
    MasterClient.cs
    Code (CSharp):
    1. public event EventHandler<string> OnAnchorHosted;
    2. public override void Start()
    3. {
    4.     m_CurrentMode = ApplicationMode.Hosting;
    5. }
    6.  
    7. public override void Update()
    8. {
    9.     base.Update();
    10.  
    11.     if (m_LastPlacedAnchor == null)
    12.     {
    13.         Touch touch;
    14.         if (Input.touchCount < 1 || (touch = Input.GetTouch(0)).phase != TouchPhase.Began)
    15.         {
    16.             return;
    17.         }
    18.  
    19.         if (Application.platform != RuntimePlatform.IPhonePlayer)
    20.         {
    21.             TrackableHit hit;
    22.             if (m_ARCoreWorldOriginHelper.Raycast(
    23.                 touch.position.x, touch.position.y,
    24.                 TrackableHitFlags.PlaneWithinPolygon, out hit))
    25.             {
    26.                 m_LastPlacedAnchor = hit.Trackable.CreateAnchor(hit.Pose);
    27.             }
    28.         }
    29.     }
    30.  
    31.     if (m_LastPlacedAnchor != null)
    32.     {
    33.         if (!m_IsOriginPlaced)
    34.         {
    35.             SetWorldOrigin(m_LastPlacedAnchor.transform);
    36.             _InstantiateAnchor();
    37.             OnAnchorInstantiated();
    38.         }
    39.     }
    40. }
    SetWorldOrigin is from the base class:
    ARPongAbstractClient.cs
    Code (CSharp):
    1.         /// <summary>
    2.         /// Sets the apparent world origin so that the Origin of Unity's World Coordinate System coincides with the
    3.         /// Anchor. This function needs to be called once the Cloud Anchor is either hosted or resolved.
    4.         /// </summary>
    5.         /// <param name="anchorTransform">Transform of the Cloud Anchor.</param>
    6.         internal void SetWorldOrigin(Transform anchorTransform)
    7.         {
    8.             if (m_IsOriginPlaced)
    9.             {
    10.                 return;
    11.             }
    12.  
    13.             m_IsOriginPlaced = true;
    14.  
    15.             if (Application.platform != RuntimePlatform.IPhonePlayer)
    16.             {
    17.                 m_ARCoreWorldOriginHelper.SetWorldOrigin(anchorTransform);
    18.             }
    19.         }
    And so we finally end up at these methods back in the ARPongMasterClient:
    Code (CSharp):
    1. private void _InstantiateAnchor()
    2. {
    3.     // Instantiate Anchor model at the hit pose.
    4.     GameObject anchorObject = PhotonNetwork.Instantiate(AnchorPrefabName, Vector3.zero, Quaternion.identity, 0);
    5.     anchorObject.transform.parent = m_LastPlacedAnchor.transform;
    6.  
    7.     // TODO Get anchor id and host in Google Cloud
    8. }
    9.  
    10. /// <summary>
    11. /// Callback indicating that the Cloud Anchor was instantiated and the host request was made.
    12. /// </summary>
    13. private void OnAnchorInstantiated()
    14. {
    15.     if (m_AnchorAlreadyInstantiated)
    16.     {
    17.         return;
    18.     }
    19.  
    20.     m_AnchorAlreadyInstantiated = true;
    21.     SnackbarText.text = "Hosting Cloud Anchor...";
    22. }
    Here is where I am stuck, currently. I don't know what to do from here. Any help would be appreciated :c
     
  2. OfficeThrashing

    OfficeThrashing

    Joined:
    May 18, 2018
    Posts:
    13
    Hi there,
    I am using ARCore Cloud anchor using photon.
    I have done changes to the existing script

    CloudAnchorsController.cs
    Code (CSharp):
    1. using GoogleARCore;
    2. using UnityEngine;
    3.  
    4. public class CloudAnchorsController : MonoBehaviour
    5. {
    6.     [Header("ARCore")]
    7.  
    8.     PhotonLobbyMatchMacking UIController;
    9.     public GameObject ARCoreRoot;
    10.     public ARCoreWorldOriginHelper ARCoreWorldOriginHelper;
    11.  
    12.     [Header("ARKit")]
    13.     public GameObject ARKitRoot;
    14.     public Camera ARKitFirstPersonCamera;
    15.     private ARKitHelper m_ARKit = new ARKitHelper();
    16.     private bool m_IsOriginPlaced = false;
    17.     private bool m_AnchorAlreadyInstantiated = false;
    18.     private bool m_AnchorFinishedHosting = false;
    19.     private bool m_IsQuitting = false;
    20.     public bool m_WaitForResponse = false;
    21.     private Component m_LastPlacedAnchor = null;
    22.     private ApplicationMode m_CurrentMode = ApplicationMode.Ready;
    23.     public enum ApplicationMode
    24.     {
    25.         Ready,
    26.         Hosting,
    27.         Resolving,
    28.     }
    29.  
    30.     TrackableHit hit;
    31.     public UnityEngine.UI.Text InfoText;
    32.     private void OnEnable()
    33.     {
    34.         Start();
    35.     }
    36.     public void Start()
    37.     {
    38.         UIController = PhotonLobbyMatchMacking.isn;
    39.         UIController.SnackbarText = InfoText;
    40.         gameObject.name = "CloudAnchorsController";
    41.         ARCoreRoot.SetActive(false);
    42.         ARKitRoot.SetActive(false);
    43.         _ResetStatus();
    44.         Debug.Log("CloudAnchorsController start");
    45.     }
    46.  
    47.     public void Update()
    48.     {
    49.         _UpdateApplicationLifecycle();
    50.        // Debug.Log(m_CurrentMode);
    51.         // If we are neither in hosting nor resolving mode then the update is complete.
    52.         if (m_CurrentMode != ApplicationMode.Hosting && m_CurrentMode != ApplicationMode.Resolving)
    53.         {
    54.             return;
    55.         }
    56.         // If the origin anchor has not been placed yet, then update in resolving mode is complete.
    57.         if (m_CurrentMode == ApplicationMode.Resolving && !m_IsOriginPlaced)
    58.         {
    59.             return;
    60.         }
    61.         // If the player has not touched the screen then the update is complete.
    62.         Touch touch;
    63.         if (Input.touchCount < 1 || ( touch = Input.GetTouch(0) ).phase != TouchPhase.Began)
    64.         {
    65.             return;
    66.         }
    67.         // Raycast against the location the player touched to search for planes.
    68.         if (Application.platform != RuntimePlatform.IPhonePlayer)
    69.         {
    70.          
    71.             if (ARCoreWorldOriginHelper.Raycast(touch.position.x , touch.position.y ,
    72.                     TrackableHitFlags.PlaneWithinPolygon , out hit))
    73.             {
    74.                 m_LastPlacedAnchor = hit.Trackable.CreateAnchor(hit.Pose);
    75.                 Debug.Log("m_LastPlacedAnchor "+ m_LastPlacedAnchor.name);
    76.             }
    77.         }
    78.         else
    79.         {
    80.             Pose hitPose;
    81.             if (m_ARKit.RaycastPlane(ARKitFirstPersonCamera , touch.position.x , touch.position.y , out hitPose))
    82.             {
    83.                 m_LastPlacedAnchor = m_ARKit.CreateAnchor(hitPose);
    84.             }
    85.         }
    86.  
    87.         // If there was an anchor placed, then instantiate the corresponding object.
    88.         if (m_LastPlacedAnchor != null)
    89.         {
    90.             Debug.Log(1);
    91.             if (!m_WaitForResponse)
    92.             {
    93.                 Debug.Log(1.1f);
    94.                 Debug.Log("The first touch on the Hosting mode will instantiate the origin anchor. Any subsequent touch will " +
    95.                  "instantiate a star, both in Hosting and Resolving modes.");
    96.                 if (_CanPlaceStars())
    97.                 {
    98.                     Debug.Log(2);
    99.                     var anchor = hit.Trackable.CreateAnchor(hit.Pose);
    100.                     // Make Andy model a child of the anchor.
    101.                     //andyObject.transform.parent = anchor.transform;
    102.                     _InstantiateStar(anchor);
    103.                 }
    104.                 else if (!m_IsOriginPlaced && m_CurrentMode == ApplicationMode.Hosting)
    105.                 {
    106.                     Debug.Log(3);
    107.                     SetWorldOrigin(m_LastPlacedAnchor.transform);
    108.                     _InstantiateAnchor();
    109.                     Debug.Log(3.1f);
    110.                     m_WaitForResponse = true;
    111.                     OnAnchorInstantiated(true);
    112.                     Debug.Log(3.2f);
    113.                 }
    114.                 Debug.Log(4);
    115.             }
    116.         }
    117.     }
    118.  
    119.     /// <summary>
    120.     /// Sets the apparent world origin so that the Origin of Unity's World Coordinate System coincides with the
    121.     /// Anchor. This function needs to be called once the Cloud Anchor is either hosted or resolved.
    122.     /// </summary>
    123.     /// <param name="anchorTransform">Transform of the Cloud Anchor.</param>
    124.     public void SetWorldOrigin(Transform anchorTransform)
    125.     {
    126.         if (m_IsOriginPlaced)
    127.         {
    128.             Debug.LogWarning("The World Origin can be set only once.");
    129.             return;
    130.         }
    131.  
    132.         m_IsOriginPlaced = true;
    133.  
    134.         if (Application.platform != RuntimePlatform.IPhonePlayer)
    135.         {
    136.             ARCoreWorldOriginHelper.SetWorldOrigin(anchorTransform);
    137.         }
    138.         else
    139.         {
    140.             m_ARKit.SetWorldOrigin(anchorTransform);
    141.         }
    142.     }
    143.  
    144.     /// <summary>
    145.     /// Handles user intent to enter a mode where they can place an anchor to host or to exit this mode if
    146.     /// already in it.
    147.     /// </summary>
    148.     public void OnEnterHostingModeClick()
    149.     {
    150.         Debug.Log(m_CurrentMode);
    151.         if (m_CurrentMode == ApplicationMode.Hosting)
    152.         {
    153.             m_CurrentMode = ApplicationMode.Ready;
    154.             _ResetStatus();
    155.             return;
    156.         }
    157.         InfoText.text = "Find a Plane and tap to Host Cloud Anchor.";
    158.         m_CurrentMode = ApplicationMode.Hosting;
    159.         _SetPlatformActive();
    160.     }
    161.  
    162.     /// <summary>
    163.     /// Handles a user intent to enter a mode where they can input an anchor to be resolved or exit this mode if
    164.     /// already in it.
    165.     /// </summary>
    166.     public void OnEnterResolvingModeClick()
    167.     {
    168.         if (m_CurrentMode == ApplicationMode.Resolving)
    169.         {
    170.             m_CurrentMode = ApplicationMode.Ready;
    171.             _ResetStatus();
    172.             return;
    173.         }
    174.         InfoText.text = "Wait for Cloud Anchor to be hosted.";
    175.         m_CurrentMode = ApplicationMode.Resolving;
    176.         _SetPlatformActive();
    177.     }
    178.  
    179.     /// <summary>
    180.     /// Callback indicating that the Cloud Anchor was instantiated and the host request was made.
    181.     /// </summary>
    182.     /// <param name="isHost">Indicates whether this player is the host.</param>
    183.     public void OnAnchorInstantiated(bool isHost)
    184.     {
    185.         if (m_AnchorAlreadyInstantiated)
    186.         {
    187.             return;
    188.         }
    189.  
    190.         m_AnchorAlreadyInstantiated = true;
    191.         UIController.OnAnchorInstantiated(isHost);
    192.     }
    193.  
    194.     /// <summary>
    195.     /// Callback indicating that the Cloud Anchor was hosted.
    196.     /// </summary>
    197.     /// <param name="success">If set to <c>true</c> indicates the Cloud Anchor was hosted successfully.</param>
    198.     /// <param name="response">The response string received.</param>
    199.     public void OnAnchorHosted(bool success , string response)
    200.     {
    201.         m_AnchorFinishedHosting = success;
    202.         UIController.OnAnchorHosted(success , response);
    203.     }
    204.  
    205.     /// <summary>
    206.     /// Callback indicating that the Cloud Anchor was resolved.
    207.     /// </summary>
    208.     /// <param name="success">If set to <c>true</c> indicates the Cloud Anchor was resolved successfully.</param>
    209.     /// <param name="response">The response string received.</param>
    210.     public void OnAnchorResolved(bool success , string response)
    211.     {
    212.         UIController.OnAnchorResolved(success , response);
    213.     }
    214.  
    215.     /// <summary>
    216.     /// Instantiates the anchor object at the pose of the m_LastPlacedAnchor Anchor. This will host the Cloud
    217.     /// Anchor.
    218.     /// </summary>
    219.     private void _InstantiateAnchor()
    220.     {
    221.         Debug.Log(5);
    222.         // The anchor will be spawned by the host, so no networking Command is needed.
    223.         GameObject.Find("LocalPlayer").GetComponent<LocalPlayerController>()
    224.                   .SpawnAnchor(Vector3.zero , Quaternion.identity , m_LastPlacedAnchor);
    225.         Debug.Log(6);
    226.     }
    227.  
    228.     /// <summary>
    229.     /// Instantiates a star object that will be synchronized over the network to other clients.
    230.     /// </summary>
    231.     ///
    232.     private void _InstantiateStar(Anchor anchor)
    233.     {
    234.         // Star must be spawned in the server so a networking Command is used.
    235.         //GameObject.Find("LocalPlayer").GetComponent<LocalPlayerController>()
    236.         //          .CmdSpawnStar(m_LastPlacedAnchor.transform.position , m_LastPlacedAnchor.transform.rotation,anchor);
    237.         Debug.Log("Request Succesfull");
    238.     }
    239.  
    240.     /// <summary>
    241.     /// Sets the corresponding platform active.
    242.     /// </summary>
    243.     private void _SetPlatformActive()
    244.     {
    245.         if (Application.platform != RuntimePlatform.IPhonePlayer)
    246.         {
    247.             ARCoreRoot.SetActive(true);
    248.             ARKitRoot.SetActive(false);
    249.         }
    250.         else
    251.         {
    252.             ARCoreRoot.SetActive(false);
    253.             ARKitRoot.SetActive(true);
    254.         }
    255.     }
    256.  
    257.     /// <summary>
    258.     /// Indicates whether a star can be placed.
    259.     /// </summary>
    260.     /// <returns><c>true</c>, if stars can be placed, <c>false</c> otherwise.</returns>
    261.     private bool _CanPlaceStars()
    262.     {
    263.         if (m_CurrentMode == ApplicationMode.Resolving)
    264.         {
    265.             return m_IsOriginPlaced;
    266.         }
    267.  
    268.         if (m_CurrentMode == ApplicationMode.Hosting)
    269.         {
    270.             return m_IsOriginPlaced && m_AnchorFinishedHosting;
    271.         }
    272.  
    273.         return false;
    274.     }
    275.  
    276.     /// <summary>
    277.     /// Resets the internal status.
    278.     /// </summary>
    279.     private void _ResetStatus()
    280.     {
    281.         // Reset internal status.
    282.         m_CurrentMode = ApplicationMode.Ready;
    283.         if (m_LastPlacedAnchor != null)
    284.         {
    285.             Destroy(m_LastPlacedAnchor.gameObject);
    286.         }
    287.  
    288.         m_LastPlacedAnchor = null;
    289.     }
    290.  
    291.     /// <summary>
    292.     /// Check and update the application lifecycle.
    293.     /// </summary>
    294.     private void _UpdateApplicationLifecycle()
    295.     {
    296.         // Exit the app when the 'back' button is pressed.
    297.         if (Input.GetKey(KeyCode.Escape))
    298.         {
    299.             Application.Quit();
    300.         }
    301.  
    302.         int sleepTimeout = SleepTimeout.NeverSleep;
    303.  
    304. #if !UNITY_IOS
    305.         // Only allow the screen to sleep when not tracking.
    306.         if (Session.Status != SessionStatus.Tracking)
    307.         {
    308.             const int lostTrackingSleepTimeout = 15;
    309.             sleepTimeout = lostTrackingSleepTimeout;
    310.         }
    311. #endif
    312.  
    313.         Screen.sleepTimeout = sleepTimeout;
    314.  
    315.         if (m_IsQuitting)
    316.         {
    317.             return;
    318.         }
    319.  
    320.         // Quit if ARCore was unable to connect and give Unity some time for the toast to appear.
    321.         if (Session.Status == SessionStatus.ErrorPermissionNotGranted)
    322.         {
    323.             _ShowAndroidToastMessage("Camera permission is needed to run this application.");
    324.             m_IsQuitting = true;
    325.             Invoke("_DoQuit" , 0.5f);
    326.         }
    327.         else if (Session.Status.IsError())
    328.         {
    329.             _ShowAndroidToastMessage("ARCore encountered a problem connecting.  Please start the app again.");
    330.             m_IsQuitting = true;
    331.             Invoke("_DoQuit" , 0.5f);
    332.         }
    333.     }
    334.  
    335.     /// <summary>
    336.     /// Actually quit the application.
    337.     /// </summary>
    338.     private void _DoQuit()
    339.     {
    340.         Application.Quit();
    341.     }
    342.  
    343.     /// <summary>
    344.     /// Show an Android toast message.
    345.     /// </summary>
    346.     /// <param name="message">Message string to show in the toast.</param>
    347.     private void _ShowAndroidToastMessage(string message)
    348.     {
    349.         AndroidJavaClass unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
    350.         AndroidJavaObject unityActivity = unityPlayer.GetStatic<AndroidJavaObject>("currentActivity");
    351.  
    352.         if (unityActivity != null)
    353.         {
    354.             AndroidJavaClass toastClass = new AndroidJavaClass("android.widget.Toast");
    355.             unityActivity.Call("runOnUiThread" , new AndroidJavaRunnable(() =>
    356.              {
    357.                  AndroidJavaObject toastObject = toastClass.CallStatic<AndroidJavaObject>("makeText" , unityActivity ,
    358.                      message , 0);
    359.                  toastObject.Call("show");
    360.              }));
    361.         }
    362.     }
    363. }
    364.  
    Another script
    AnchorController.cs

    Code (CSharp):
    1. //-----------------------------------------------------------------------
    2. // <copyright file="AnchorController.cs" company="Google">
    3. //
    4. // Copyright 2018 Google Inc. All Rights Reserved.
    5. //
    6. // Licensed under the Apache License, Version 2.0 (the "License");
    7. // you may not use this file except in compliance with the License.
    8. // You may obtain a copy of the License at
    9. //
    10. // http://www.apache.org/licenses/LICENSE-2.0
    11. //
    12. // Unless required by applicable law or agreed to in writing, software
    13. // distributed under the License is distributed on an "AS IS" BASIS,
    14. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    15. // See the License for the specific language governing permissions and
    16. // limitations under the License.
    17. //
    18. // </copyright>
    19. //-----------------------------------------------------------------------
    20.  
    21. using GoogleARCore;
    22. using GoogleARCore.CrossPlatform;
    23. using Photon.Pun;
    24. using UnityEngine;
    25.  
    26. /// <summary>
    27. /// A Controller for the Anchor object that handles hosting and resolving the Cloud Anchor.
    28. /// </summary>
    29. public class AnchorController : MonoBehaviourPunCallbacks, IPunObservable
    30. {
    31.  
    32.     public PhotonView pv;
    33.     /// <summary>
    34.     /// The Cloud Anchor ID that will be used to host and resolve the Cloud Anchor. This variable will be
    35.     /// syncrhonized over all clients.
    36.     /// </summary>
    37.     public string m_CloudAnchorId = string.Empty;
    38.  
    39.     /// <summary>
    40.     /// Indicates whether this script is running in the Host.
    41.     /// </summary>
    42.     private bool m_IsHost = false;
    43.  
    44.     /// <summary>
    45.     /// Indicates whether an attempt to resolve the Cloud Anchor should be made.
    46.     /// </summary>
    47.     private bool m_ShouldResolve = false;
    48.  
    49.  
    50.     /// <summary>
    51.     /// If there is an error in resolving the anchore we should wait for some time
    52.     /// as there is Limited quota for Read and Write anchors.
    53.     /// follow the link for more Information.
    54.     /// https://developers.google.com/ar/develop/java/cloud-anchors/developer-guide-android
    55.     /// </summary>
    56.     private bool m_ThereisError_Wait = false;
    57.  
    58.  
    59.     /// <summary>
    60.     /// The Cloud Anchors example controller.
    61.     /// </summary>
    62.     private CloudAnchorsController m_CloudAnchorsController;
    63.  
    64.  
    65.     public bool isError;
    66.     /// <summary>
    67.     /// The Unity Start() method.
    68.     /// </summary>
    69.     public void Start()
    70.     {
    71.         pv = GetComponent<PhotonView>();
    72.         m_CloudAnchorsController = GameObject.Find("CloudAnchorsController").GetComponent<CloudAnchorsController>();
    73.         m_CloudAnchorsController.ARCoreWorldOriginHelper.enabled = false;
    74.  
    75.         if (!pv.IsMine)
    76.         {
    77.             Debug.Log("this is not mine", gameObject);
    78.             OnStartClient();
    79.         }
    80.     }
    81.  
    82.     /// <summary>
    83.     /// The Unity OnStartClient() method.
    84.     /// </summary>
    85.     public void OnStartClient()
    86.     {
    87.         if (m_CloudAnchorId != string.Empty)
    88.         {
    89.             m_ShouldResolve = true;
    90.         }
    91.         else
    92.         {
    93.             PhotonLobbyMatchMacking.isn.SnackbarText.text = "Cloud Anchor has been Instantiated , wait for it be hosted on cloud";
    94.         }
    95.     }
    96.  
    97.     /// <summary>
    98.     /// The Unity Update() method.
    99.     /// </summary>
    100.     public void Update()
    101.     {
    102.         if (!m_ThereisError_Wait)
    103.         {
    104.             if (m_CloudAnchorId != string.Empty)
    105.             {
    106.                 m_ShouldResolve = true;
    107.             }
    108.             if (m_ShouldResolve)
    109.             {
    110.                 _ResolveAnchorFromId(m_CloudAnchorId);
    111.             }
    112.         }
    113.     }
    114.  
    115.     /// <summary>
    116.     /// Command run on the server to set the Cloud Anchor Id.
    117.     /// </summary>
    118.     /// <param name="cloudAnchorId">The new Cloud Anchor Id.</param>
    119.     [PunRPC]
    120.     public void PunRpcSetCloudAnchorId( string cloudAnchorId )
    121.     {
    122.         m_CloudAnchorId = cloudAnchorId;
    123.     }
    124.  
    125.     /// <summary>
    126.     /// Gets the Cloud Anchor Id.
    127.     /// </summary>
    128.     /// <returns>The Cloud Anchor Id.</returns>
    129.     public string GetCloudAnchorId()
    130.     {
    131.         return m_CloudAnchorId;
    132.     }
    133.  
    134.     /// <summary>
    135.     /// Hosts the user placed cloud anchor and associates the resulting Id with this object.
    136.     /// </summary>
    137.     /// <param name="lastPlacedAnchor">The last placed anchor.</param>
    138.     private int HowManyTimesErrorOccurd = 1;
    139.     public void HostLastPlacedAnchor( Component lastPlacedAnchor )
    140.     {
    141.         m_IsHost = true;
    142.  
    143. #if !UNITY_IOS
    144.         Anchor anchor = (Anchor)lastPlacedAnchor;
    145. #elif ARCORE_IOS_SUPPORT
    146.             var anchor = (UnityEngine.XR.iOS.UnityARUserAnchorComponent)lastPlacedAnchor;
    147. #endif
    148.  
    149. #if !UNITY_IOS || ARCORE_IOS_SUPPORT
    150.         XPSession.CreateCloudAnchor(anchor).ThenAction(result =>
    151.         {
    152.             if (result.Response != CloudServiceResponse.Success)
    153.             {
    154.                 Debug.Log(string.Format("Failed to host Cloud Anchor: {0}", result.Response));
    155.  
    156.                 m_CloudAnchorsController.OnAnchorHosted(false, result.Response.ToString());
    157.                 StartCoroutine(ThereisAnError(HowManyTimesErrorOccurd));
    158.                 HowManyTimesErrorOccurd += 1;
    159.                 return;
    160.             }
    161.  
    162.             Debug.Log(string.Format("Cloud Anchor {0} was created and saved.", result.Anchor.CloudId));
    163.             pv.RPC("PunRpcSetCloudAnchorId", RpcTarget.AllBufferedViaServer, result.Anchor.CloudId);
    164.             //PunRpcSetCloudAnchorId(result.Anchor.CloudId);//Set the
    165.  
    166.             m_CloudAnchorsController.OnAnchorHosted(true, result.Response.ToString());
    167.         });
    168.  
    169. #endif
    170.     }
    171.  
    172.     private System.Collections.IEnumerator ThereisAnError( int i )
    173.     {
    174.         m_ThereisError_Wait = true;
    175.         yield return new WaitForSeconds(2 * i);
    176.         m_ThereisError_Wait = false;
    177.     }
    178.     /// <summary>
    179.     /// Resolves an anchor id and instantiates an Anchor prefab on it.
    180.     /// </summary>
    181.     /// <param name="cloudAnchorId">Cloud anchor id to be resolved.</param>
    182.     private void _ResolveAnchorFromId( string cloudAnchorId )
    183.     {
    184.         m_CloudAnchorsController.OnAnchorInstantiated(false);
    185.  
    186.         // If device is not tracking, let's wait to try to resolve the anchor.
    187.         if (Session.Status != SessionStatus.Tracking)
    188.         {
    189.             return;
    190.         }
    191.  
    192.         m_ShouldResolve = false;
    193.  
    194.         XPSession.ResolveCloudAnchor(cloudAnchorId).ThenAction(result =>
    195.         {
    196.             if (HowManyTimesErrorOccurd < 300 && !GameManagerWR.isn.isLeft && !GameManagerWR.isn.isResolved)
    197.             {
    198.                 if (result.Response != CloudServiceResponse.Success)
    199.                 {
    200.                     Debug.LogError(string.Format("Client could not resolve Cloud Anchor {0}: {1} , The Read request number is {2}",
    201.                                                  cloudAnchorId, result.Response, HowManyTimesErrorOccurd));
    202.                     Debug.Log("1");
    203.                     m_CloudAnchorsController.OnAnchorResolved(false, result.Response.ToString());
    204.                     Debug.Log("2");
    205.                     StartCoroutine(ThereisAnError(HowManyTimesErrorOccurd));
    206.                     Debug.Log("3");
    207.                     HowManyTimesErrorOccurd += 1;
    208.                     Debug.Log("4");
    209.                     m_ShouldResolve = true;
    210.                     return;
    211.                 }
    212.  
    213.                 Debug.Log(string.Format("Client successfully resolved Cloud Anchor {0}.",
    214.                                         cloudAnchorId));
    215.  
    216.                 GameManagerWR.isn.isResolved = true;
    217.                 m_ShouldResolve = false;
    218.                 m_CloudAnchorsController.OnAnchorResolved(true, result.Response.ToString());
    219.                 _OnResolved(result.Anchor.transform);
    220.                 m_CloudAnchorsController.m_WaitForResponse = false;
    221.                 //this.enabled = false;
    222.  
    223.                 //GetComponent<MeshRenderer>().enabled = false;
    224.             }
    225.         });
    226.     }
    227.     /// <summary>
    228.     /// Callback invoked once the Cloud Anchor is resolved.
    229.     /// </summary>
    230.     /// <param name="anchorTransform">Transform of the resolved Cloud Anchor.</param>
    231.     private void _OnResolved( Transform anchorTransform )
    232.     {
    233.         CloudAnchorsController cloudAnchorController = GameObject.Find("CloudAnchorsController")
    234.                                                   .GetComponent<CloudAnchorsController>();
    235.         cloudAnchorController.SetWorldOrigin(anchorTransform);
    236.     }
    237.  
    238.     /// <summary>
    239.     /// Callback invoked once the Cloud Anchor Id changes.
    240.     /// </summary>
    241.     /// <param name="newId">New identifier.</param>
    242.     private void _OnChangeId( string newId )
    243.     {
    244.         if (!m_IsHost && newId != string.Empty)
    245.         {
    246.             m_CloudAnchorId = newId;
    247.             m_ShouldResolve = true;
    248.         }
    249.     }
    250.  
    251.     public void OnPhotonSerializeView( PhotonStream stream, PhotonMessageInfo info )
    252.     {
    253.         throw new System.NotImplementedException();
    254.     }
    255. }
    256.  
     
  3. fxmediamark

    fxmediamark

    Joined:
    Oct 19, 2013
    Posts:
    5
    Hi, @OfficeThrashing are the scripts still working? I try to use the scripts but got error photonlobbymatchmacking class not found. Which version of the PUN you're using? or that class is simply a class to manage the matchmacking?
     
  4. OfficeThrashing

    OfficeThrashing

    Joined:
    May 18, 2018
    Posts:
    13
    Remove the dependencies or comment on the errors.
    replace this two script with the scripts that are in the ARCore plugin.

    The first script is responsible for Hosting Cloud anchor and the second script is for Resolving it
    I just changed the Unet syntax with photon that's it.
     
  5. Vinayak-VC

    Vinayak-VC

    Joined:
    Apr 16, 2019
    Posts:
    60
  6. fxmediamark

    fxmediamark

    Joined:
    Oct 19, 2013
    Posts:
    5
    @WR-reddevil need to did some more change for that, and I don't know why but I cannot seem to detect room created from android in iOS. Well, I use the unet system for now
     
  7. Vinayak-VC

    Vinayak-VC

    Joined:
    Apr 16, 2019
    Posts:
    60
    @fxmediamark I think these two scripts will come in scene after the room is created

    I mean flow can be like
    1. Join Lobby
    2. Create or join Room
    3. Master client will instantiate the environment and host the cloud anchors
    4. The client will resolve the anchor and then Instantiate the players.

    Correct me if I am wrong
    1st & 2nd step will be normal Photon Room creation and join
    in the 3rd & 4th step will require those two scripts to host and resolve the anchors.

    And if you don't want to use cloud anchor and just want the experience of AR
    then this flow can help you,
     
  8. Hamburgerfc

    Hamburgerfc

    Joined:
    Oct 22, 2019
    Posts:
    2
    Hi @fxmediamark @WR-reddevil

    I am trying to achieve the same thing with Photon and AR Core SDK. Is there any chance a working example could be uploaded?
     
  9. sumoujou

    sumoujou

    Joined:
    Feb 7, 2017
    Posts:
    2
    @Hamburgerfc

    Did you have any luck with this?
     
  10. Hamburgerfc

    Hamburgerfc

    Joined:
    Oct 22, 2019
    Posts:
    2
    Unfortunately not, I was under a strict time frame and so for my application my workaround was simply have both users host the map instead of using one single anchor. Any updates made by a player on their map would be sent through a PunRPC method so all clients in the room get the update.
     
  11. jaweherncir

    jaweherncir

    Joined:
    Apr 29, 2020
    Posts:
    5
    Hello please i need help very urgent, somone h3lp. Me !!! How con i create room with arcore some script or video to help me !!!!