public void JoinRoom(string roomToJoin, string userName) { Debug.Assert(!string.IsNullOrEmpty(userName), "Username cannot be null or empty"); RoomName = roomToJoin; localUserName = userName; if (NeuraCore.Instance.socket == null || !NeuraCore.Instance.socket.isConnected) { print("Not connected, trying to auto connect"); OnConnected += AutoJoinRoom; Connect(); return; } if (inRoom) { print("Cannot join room when already in one"); return; } globalState = new RoomStateGen(); requestedSiteDrive = ""; requestedPoi = new TargetPlacementObject(); requestedAnnotation = new AnnotationObject(); requestedAnnotationDeletions = new List <AnnotationObject>(); NeuraCore.Instance.JoinRoom(roomToJoin, userName); }
public void CleanState() { NeuraCore.Instance.ForceClosed(); foreach (KeyValuePair <int, ITrackable> trackable in trackers) { if (trackable.Value != null) { Destroy(((MonoBehaviour)trackable.Value).gameObject); } } trackers = new Dictionary <int, ITrackable>(); globalState = new RoomStateGen(); }
public IEnumerator Start() { globalState = new RoomStateGen(); WaitForEndOfFrame w = new WaitForEndOfFrame(); NeuraCore.Instance.OnError += ErrorHandler; NeuraCore.Instance.OnClose += CloseHandler; NeuraCore.Instance.OnOpen += OpenHandler; NeuraCore.Instance.OnMessage += MessageHandler; InvokeRepeating("RefreshRoomList", 0.1f, 2f); while (NeuraCore.Instance.socket == null) { yield return(w); } updateTime = 1f / NeuraCore.Instance.config.UpdateHz; }
public void JoinRoom(string roomToJoin, string userName) { Debug.Assert(!string.IsNullOrEmpty(userName), "Username cannot be null or empty"); RoomName = roomToJoin; localUserName = userName; if (NeuraCore.Instance.socket == null || !NeuraCore.Instance.socket.isConnected) { print("Not connected, trying to auto connect"); OnConnected += AutoJoinRoom; Connect(); return; } if (inRoom) { print("Cannot join room when already in one"); return; } globalState = new RoomStateGen(); NeuraCore.Instance.JoinRoom(roomToJoin, userName); }
/// <summary> /// Creates a local copy of a remote object /// </summary> /// <param name="newObj"></param> private void CreateObject(RoomObjectObj newObj, RoomStateGen state) { print("Creating object " + newObj.name); ITrackable tracker; GameObject go; if (prefabNames.Contains(newObj.prefab)) { go = Instantiate <GameObject>(prefabs[prefabNames.IndexOf(newObj.prefab)]); tracker = go.GetComponent <ITrackable>(); } else { go = new GameObject("Prefab " + newObj.prefab + " not found"); tracker = go.AddComponent <NStateTracker>(); } tracker.id = newObj.id; tracker.prefab = newObj.prefab; trackers.Add(tracker.id, tracker); state.objects.Add(newObj); roomCreatedObjects.Add(go); tracker.UpdateFromRoomObject(newObj); }
private void MessageHandler(object sender, MessageEventArgs e) { var bb = new ByteBuffer(e.RawData); ServerMessage msg = ServerMessage.GetRootAsServerMessage(bb); switch (msg.Type) { case msgType.RoomStateUpdate: //handle message if (msg.Data <StateUpdate>() == null) { print("empty state update. this should not happen"); return; } StateUpdate?stateUpdate = msg.Data <StateUpdate>(); if (stateUpdate != null) { StateUpdate sup = stateUpdate.Value; UpdateLocalState(sup); } break; case msgType.SocketReady: print("connected to server"); StringData?stringData = msg.Data <StringData>(); if (stringData != null) { OnConnectedArgs connectedEventArgs = new OnConnectedArgs { sid = stringData.Value.Data, }; NeuraCore.Instance.sid = connectedEventArgs.sid; } if (OnConnected != null) { OnConnected.Invoke(this, new EventArgs()); } break; case msgType.SocketRoomJoined: { print("Joined room "); inRoom = true; UsersInRoom.Add(localUserName); NeuraCore.Instance.connectionState = ConnectionState.Connected; if (msg.DataType != Transport.FlatBuffers.msg.StateUpdate) { return; } if (msg.Data <StateUpdate>().HasValue) { var initStateSUP = msg.Data <StateUpdate>().Value; UpdateLocalState(initStateSUP); } if (OnRoomJoined != null) { OnRoomJoined.Invoke(this, RoomName); } } break; case msgType.RoomCreated: StringData?createMsg = msg.Data <StringData>(); if (createMsg != null) { //var rmName = createMsg.Value.Data; //RoomName = rmName; print("room " + RoomName + " has been created"); if (OnRoomCreated != null) { OnRoomCreated.Invoke(this, RoomName); } if (string.IsNullOrEmpty((globalState ?? (globalState = new RoomStateGen())).siteDrive)) { //Handle things like critical room state here to make sure that the initial state sent has the required information //For onsight the site drive is of critical importance so we are setting it below //globalState.siteDrive = string.IsNullOrEmpty(requestedSiteDrive) // ? MultiUserConnectionManager.Instance.CurrentSiteDriveJSON // : requestedSiteDrive; } Debug.Assert(!string.IsNullOrEmpty(globalState.siteDrive)); NeuraCore.Instance.SendInitialState(ServerMessageFactory.BuildMessage(globalState)); } break; case msgType.RoomUserOnjoined: StringData?joinedMsg = msg.Data <StringData>(); if (joinedMsg != null) { var user = joinedMsg.Value.Data; print(user + " has joined the room"); UsersInRoom.Add(user); if (OnUserJoined != null) { OnUserJoined.Invoke(this, new UserJoinedEventArgs { username = user }); } } break; case msgType.RoomUserOnLeft: StringData?leftMsg = msg.Data <StringData>(); if (leftMsg != null) { var user = leftMsg.Value.Data; print(user + " has left the room"); if (UsersInRoom.Contains(user)) { UsersInRoom.Remove(user); } if (OnUserLeft != null) { OnUserLeft.Invoke(this, new UserLeftEventArgs { username = user }); } } break; } }
/// <summary> /// Upload any changes in objects owned by the local player, in scene properties, or scene objects /// </summary> private void UploadGlobalState() { lastUpdate = Time.realtimeSinceStartup; if (!inRoom) { return; } List <RoomObjectObj> localObjectsUpdate = new List <RoomObjectObj>(); StateUpdateObject diffState = null; #region Object Updates if (globalState.objects != null) { foreach (RoomObjectObj obj in globalState.objects) { if (!trackers[obj.id].isLocal) { continue; } if (!CompareObjects(obj, trackers[obj.id].ToRoomObject())) { localObjectsUpdate.Add(trackers[obj.id].ToRoomObject()); } } //update the local copy of the global state with the new values for player controlled and scene objects for (int i = 0; i < localObjectsUpdate.Count; i++) { globalState.objects[globalState.objects.IndexOf(localObjectsUpdate[i])] = localObjectsUpdate[i]; } if (localObjectsUpdate.Count != 0 || newRoomObjects.Count != 0) { diffState = new StateUpdateObject { update = localObjectsUpdate }; if (newRoomObjects.Count > 0) { diffState.create = newRoomObjects; } newRoomObjects = new List <RoomObjectObj>(); } } else { print("globalState has no objects"); } #endregion #region Property Updates if (!string.IsNullOrEmpty(requestedSiteDrive)) //update scene { print("site drive changed in global"); var mutState = diffState ?? (diffState = new StateUpdateObject()); mutState.siteDrive = requestedSiteDrive; requestedSiteDrive = ""; oldSiteDrive = ""; } if (requestedPoi.isValid) { print("Setting requested poi"); var mutState = diffState ?? (diffState = new StateUpdateObject()); mutState.PlacePoi(requestedPoi); requestedPoi.isValid = false; } if (requestedAnnotation.isValid) { print("Adding requested annotation"); var mutState = diffState ?? (diffState = new StateUpdateObject()); mutState.AddAnnotation(requestedAnnotation); requestedAnnotation.isValid = false; } if (requestedAnnotationDeletions != null) { var mutState = diffState ?? (diffState = new StateUpdateObject()); for (int i = 0; i < requestedAnnotationDeletions.Count; i++) { var del = requestedAnnotationDeletions[i]; del.positions = new UnityEngine.Vector3[0]; del.isValid = true; mutState.AddAnnotation(del); } requestedAnnotationDeletions = null; } #endregion if (diffState != null ) //Serialize the updates to json and pass them to the NeuraCore to be sent to the server { NeuraCore.Instance.SetUpdate(ServerMessageFactory.BuildMessage(diffState)); } //Find all local owned and scene objects that have changed since the last tick oldStateGen = new RoomStateGen(globalState); }
/// <summary> /// Updates the local copy of the global state via server delta /// </summary> /// <param name="serverUpdate">changes to the global state since last server tick</param> private void UpdateLocalState(StateUpdate serverUpdate) { RoomStateGen newRoomState = new RoomStateGen(globalState); #region properties update bool propsChanged = false; bool isSceneUpdate = false; if (!string.IsNullOrEmpty(serverUpdate.SiteDrive)) { propsChanged = true; isSceneUpdate = true; } else { if (serverUpdate.AnnotationsLength > 0) { propsChanged = true; } if (serverUpdate.Poi.HasValue) { propsChanged = true; } } if (propsChanged) { if (isSceneUpdate) { if (OnPropertiesChanged != null) { OnPropertiesChanged.Invoke(this, serverUpdate); } } else { serverUpdate.Debounce(this, props => { if (OnPropertiesChanged != null) { OnPropertiesChanged.Invoke(this, props); } }, isSceneUpdate); } } #endregion if (serverUpdate.DeleteLength > 0) //delete these object ids from the global state { print("Deleting " + serverUpdate.DeleteLength + " objects"); for (int i = 0; i < serverUpdate.DeleteLength; i++) { if (newRoomState.objects.All(tr => tr.id != serverUpdate.Delete(i))) { print("object to delete not found in global state " + serverUpdate.Delete(i)); continue; } newRoomState.objects.Remove(globalState.objects.Single(o => o.id == serverUpdate.Delete(i))); if (trackers.ContainsKey(serverUpdate.Delete(i)) && trackers[serverUpdate.Delete(i)] != null) { Destroy(((MonoBehaviour)trackers[serverUpdate.Delete(i)]).gameObject); } else { print("Could not find game object to destroy" + serverUpdate.Delete(i)); } } } if (serverUpdate.CreateLength > 0) //create these objects and add them to the global state { for (int i = 0; i < serverUpdate.CreateLength; i++) { if (!serverUpdate.Create(i).HasValue) { print("Malformed create message"); continue; } if (!trackers.ContainsKey(serverUpdate.Create(i).Value.Id)) { CreateObject(serverUpdate.Create(i).Value, newRoomState); //if (newRoomState.objects.Contains(serverUpdate.Create(i).Value)) //continue; } else { print("Object " + serverUpdate.Create(i).Value.Id + " already exists"); } //else //{ // if (newRoomState.objects.Any(tr => tr.id == serverUpdate.Create(i).Value.Id)) // newRoomState.objects.Remove(newRoomState.objects.Single(o => o.id == serverUpdate.Create(i).Value.Id)); // var oldObj = (MonoBehaviour) trackers[serverUpdate.Create(i).Value.Id]; // if (oldObj) Destroy(oldObj.gameObject); // trackers.Remove(serverUpdate.Create(i).Value.Id); //} //CreateObject(serverUpdate.Create(i).Value, newRoomState); } } if (serverUpdate.UpdateLength > 0) { for (int i = 0; i < serverUpdate.UpdateLength; i++) { if (!serverUpdate.Update(i).HasValue) { continue; } if (!trackers.ContainsKey(serverUpdate.Update(i).Value.Id)) { Debug.Log("Object created from update. please use the create function instead"); //CreateObject(serverUpdate.Update(i).Value, newRoomState); continue; } trackers[serverUpdate.Update(i).Value.Id].UpdateFromRoomObject(serverUpdate.Update(i).Value); } } oldStateGen = new RoomStateGen(globalState); globalState = newRoomState; }
/// <summary> /// Upload any changes in objects owned by the local player, in scene properties, or scene objects /// </summary> private void UploadGlobalState() { lastUpdate = Time.realtimeSinceStartup; if (!inRoom) { return; } List <RoomObjectObj> localObjectsUpdate = new List <RoomObjectObj>(); StateUpdateObject diffState = null; #region Object Updates if (globalState.objects != null) { foreach (RoomObjectObj obj in globalState.objects) { if (!trackers[obj.id].isLocal) { continue; } if (!CompareObjects(obj, trackers[obj.id].ToRoomObject())) { localObjectsUpdate.Add(trackers[obj.id].ToRoomObject()); } } //update the local copy of the global state with the new values for player controlled and scene objects for (int i = 0; i < localObjectsUpdate.Count; i++) { globalState.objects[globalState.objects.IndexOf(localObjectsUpdate[i])] = localObjectsUpdate[i]; } if (localObjectsUpdate.Count != 0 || newRoomObjects.Count != 0) { diffState = new StateUpdateObject { update = localObjectsUpdate }; if (newRoomObjects.Count > 0) { diffState.create = newRoomObjects; } newRoomObjects = new List <RoomObjectObj>(); } } else { print("globalState has no objects"); } #endregion #region Property Updates #endregion if (diffState != null ) //Serialize the updates to json and pass them to the NeuraCore to be sent to the server { NeuraCore.Instance.SetUpdate(ServerMessageFactory.BuildMessage(diffState)); } //Find all local owned and scene objects that have changed since the last tick oldStateGen = new RoomStateGen(globalState); }
/// <summary> /// Updates the local copy of the global state via server delta /// </summary> /// <param name="serverUpdate">changes to the global state since last server tick</param> private void UpdateLocalState(StateUpdate serverUpdate) { RoomStateGen newRoomState = new RoomStateGen(globalState); #region properties update bool propsChanged = false; if (propsChanged) { } #endregion if (serverUpdate.DeleteLength > 0) //delete these object ids from the global state { print("Deleting " + serverUpdate.DeleteLength + " objects"); for (int i = 0; i < serverUpdate.DeleteLength; i++) { if (newRoomState.objects.All(tr => tr.id != serverUpdate.Delete(i))) { print("object to delete not found in global state " + serverUpdate.Delete(i)); continue; } newRoomState.objects.Remove(globalState.objects.Single(o => o.id == serverUpdate.Delete(i))); if (trackers.ContainsKey(serverUpdate.Delete(i)) && trackers[serverUpdate.Delete(i)] != null) { Destroy(((MonoBehaviour)trackers[serverUpdate.Delete(i)]).gameObject); } else { print("Could not find game object to destroy" + serverUpdate.Delete(i)); } } } if (serverUpdate.CreateLength > 0) //create these objects and add them to the global state { for (int i = 0; i < serverUpdate.CreateLength; i++) { if (!serverUpdate.Create(i).HasValue) { print("Malformed create message"); continue; } if (!trackers.ContainsKey(serverUpdate.Create(i).Value.Id)) { CreateObject(serverUpdate.Create(i).Value, newRoomState); //if (newRoomState.objects.Contains(serverUpdate.Create(i).Value)) //continue; } else { print("Object " + serverUpdate.Create(i).Value.Id + " already exists"); } } } if (serverUpdate.UpdateLength > 0) { for (int i = 0; i < serverUpdate.UpdateLength; i++) { if (!serverUpdate.Update(i).HasValue) { continue; } if (!trackers.ContainsKey(serverUpdate.Update(i).Value.Id)) { Debug.Log("Object created from update. please use the create function instead"); //CreateObject(serverUpdate.Update(i).Value, newRoomState); continue; } trackers[serverUpdate.Update(i).Value.Id].UpdateFromRoomObject(serverUpdate.Update(i).Value); } } oldStateGen = new RoomStateGen(globalState); globalState = newRoomState; }