AR Design
UBC EML collab with UBC SALA - visualizing IoT data in AR
NetworkDiscoveryWithAnchors.cs
Go to the documentation of this file.
1 // Copyright (c) Microsoft Corporation. All rights reserved.
2 // Licensed under the MIT License. See LICENSE in the project root for license information.
3 
4 using System;
5 using System.Collections;
6 using System.Collections.Generic;
7 using UnityEngine;
8 using UnityEngine.Networking;
9 
10 #if !UNITY_EDITOR && UNITY_WSA
11 using Windows.Networking;
12 using Windows.Networking.Connectivity;
13 #endif
14 
15 namespace HoloToolkit.Unity.SharingWithUNET
16 {
25  public class NetworkDiscoveryWithAnchors : NetworkDiscovery
26  {
30  private static NetworkDiscoveryWithAnchors _Instance;
31  public static NetworkDiscoveryWithAnchors Instance
32  {
33  get
34  {
35  NetworkDiscoveryWithAnchors[] objects = FindObjectsOfType<NetworkDiscoveryWithAnchors>();
36  if (objects.Length != 1)
37  {
38  Debug.LogFormat("Expected exactly 1 {0} but found {1}", typeof(NetworkDiscoveryWithAnchors).ToString(), objects.Length);
39  }
40  else
41  {
42  _Instance = objects[0];
43  }
44  return _Instance;
45  }
46  }
47 
51  public class SessionInfo
52  {
53  public string SessionName;
54  public string SessionIp;
55  }
56 
60  public bool Connected
61  {
62  get
63  {
64  // We are connected if we are the server or if we aren't running discovery
65  return (isServer || !running);
66  }
67  }
68 
72  public event EventHandler<EventArgs> SessionListChanged;
73 
77  [HideInInspector]
78  public Dictionary<string, SessionInfo> remoteSessions = new Dictionary<string, SessionInfo>();
79 
83  public event EventHandler<EventArgs> ConnectionStatusChanged;
84 
89  public int BroadcastInterval = 1000;
90 
96  public string ServerIp { get; private set; }
97 
101  public string LocalIp { get; set; }
102 
107  private bool CheckComponents()
108  {
109 #if !UNITY_EDITOR && UNITY_WSA
111  {
112  Debug.Log("Need a UNetNetworkTransmitter in the scene for sending anchor data");
113  return false;
114  }
115 #endif
116  if (NetworkManager.singleton == null)
117  {
118  Debug.Log("Need a NetworkManager in the scene");
119  return false;
120  }
121 
122  return true;
123  }
124 
125  private void Awake()
126  {
127 #if !UNITY_EDITOR && UNITY_WSA
128  // Find our local IP
129  foreach (HostName hostName in NetworkInformation.GetHostNames())
130  {
131  if (hostName.DisplayName.Split(".".ToCharArray()).Length == 4)
132  {
133  Debug.Log("Local IP " + hostName.DisplayName);
134  LocalIp = hostName.DisplayName;
135  break;
136  }
137  }
138 #else
139  LocalIp = "editor" + UnityEngine.Random.Range(0, 999999).ToString(); ;
140 #endif
141  }
142 
143  private void Start()
144  {
145  // Initializes NetworkDiscovery.
146  Initialize();
147 
148  if (!CheckComponents())
149  {
150  Debug.Log("Invalid configuration detected. Network Discovery disabled.");
151  Destroy(this);
152  return;
153  }
154 
155  broadcastInterval = BroadcastInterval;
156  // Add our computer name to the broadcast data for use in the session name.
157  broadcastData = GetLocalComputerName() + '\0';
158 
159  // Start listening for broadcasts.
160  StartAsClient();
161  }
162 
167  private string GetLocalComputerName()
168  {
169 #if !UNITY_EDITOR && UNITY_WSA
170  foreach (HostName hostName in NetworkInformation.GetHostNames())
171  {
172  if (hostName.Type == HostNameType.DomainName)
173  {
174 
175  Debug.Log("My name is " + hostName.DisplayName);
176  return hostName.DisplayName;
177  }
178  }
179  return "NotSureWhatMyNameIs";
180 #else
181  return System.Environment.ExpandEnvironmentVariables("%ComputerName%");
182 #endif
183  }
184 
189  private void MaybeInitAsServer()
190  {
191  StartCoroutine(InitAsServer());
192  }
193 
194  private IEnumerator InitAsServer()
195  {
196  Debug.Log("Acting as host");
197 #if !UNITY_EDITOR && UNITY_WSA
198  NetworkManager.singleton.serverBindToIP = true;
199  NetworkManager.singleton.serverBindAddress = LocalIp;
200 #endif
201 
202  // StopBroadcast will also 'StopListening'
203  StopBroadcast();
204 
205  // Work-around when building to the HoloLens with "Compile with .NET Native tool chain".
206  // Need a frame of delay after StopBroadcast() otherwise clients won't connect.
207  yield return null;
208 
209  // Starting as a 'host' makes us both a client and a server.
210  // There are nuances to this in UNet's sync system, so do make sure
211  // to test behavior of your networked objects on both a host and a client
212  // device.
213  NetworkManager.singleton.StartHost();
214 
215  // Work-around when building to the HoloLens with "Compile with .NET Native tool chain".
216  // Need a frame of delay between StartHost() and StartAsServer() otherwise clients won't connect.
217  yield return null;
218 
219  // Start broadcasting for other clients.
220  StartAsServer();
221 
222 #if !UNITY_EDITOR && UNITY_WSA
223  // Start creating an anchor.
225 #else
226  Debug.LogWarning("This script will need modification to work in the Unity Editor");
227 #endif
228  }
229 
236  public override void OnReceivedBroadcast(string fromAddress, string data)
237  {
238  ServerIp = fromAddress.Substring(fromAddress.LastIndexOf(':') + 1);
239  SessionInfo sessionInfo;
240  if (remoteSessions.TryGetValue(ServerIp, out sessionInfo) == false)
241  {
242  Debug.Log("new session: " + fromAddress);
243  Debug.Log(data);
244  remoteSessions.Add(ServerIp, new SessionInfo() { SessionIp = ServerIp, SessionName = data });
245  SignalSessionListEvent();
246  }
247  }
248 
249 
253  public void StopListening()
254  {
255  StopBroadcast();
256  remoteSessions.Clear();
257  }
258 
262  public void StartListening()
263  {
264  StopListening();
265  StartAsClient();
266  }
267 
272  public void JoinSession(SessionInfo session)
273  {
274  StopListening();
275  // We have to parse the server IP to make the string friendly to the windows APIs.
276  ServerIp = session.SessionIp;
277  NetworkManager.singleton.networkAddress = ServerIp;
278 #if !UNITY_EDITOR && UNITY_WSA
279  // Tell the network transmitter the IP to request anchor data from if needed.
280  GenericNetworkTransmitter.Instance.SetServerIp(ServerIp);
281 #else
282  Debug.LogWarning("This script will need modification to work in the Unity Editor");
283 #endif
284  // And join the networked experience as a client.
285  NetworkManager.singleton.StartClient();
286  SignalConnectionStatusEvent();
287  }
288 
293  public void StartHosting(string SessionName)
294  {
295  StopListening();
296 
297 #if !UNITY_EDITOR && UNITY_WSA
298  NetworkManager.singleton.serverBindToIP = true;
299  NetworkManager.singleton.serverBindAddress = LocalIp;
300 #endif
301  // Starting as a 'host' makes us both a client and a server.
302  // There are nuances to this in UNet's sync system, so do make sure
303  // to test behavior of your networked objects on both a host and a client
304  // device.
305  NetworkManager.singleton.StartHost();
306  // Start broadcasting for other clients.
307  StartAsServer();
308 
309 #if !UNITY_EDITOR && UNITY_WSA
310  // Invoke creating an anchor in a couple frames to give all the Unet network objects time to spawn.
311  Invoke("InvokeCreateAnchor", 0.25f);
312 #else
313  Debug.LogWarning("This script will need modification to work in the Unity Editor");
314 #endif
315 
316  SignalSessionListEvent();
317  SignalConnectionStatusEvent();
318  }
319 
324  void InvokeCreateAnchor()
325  {
327  }
328 
332  void SignalSessionListEvent()
333  {
334  EventHandler<EventArgs> sessionListChanged = SessionListChanged;
335  if (sessionListChanged != null)
336  {
337  sessionListChanged(this, EventArgs.Empty);
338  }
339  }
340 
344  void SignalConnectionStatusEvent()
345  {
346  EventHandler<EventArgs> connectionEvent = this.ConnectionStatusChanged;
347  if (connectionEvent != null)
348  {
349  connectionEvent(this, EventArgs.Empty);
350  }
351  }
352  }
353 }
Inherits from UNet&#39;s NetworkDiscovery script. Adds automatic anchor management on discovery...
void JoinSession(SessionInfo session)
Call to join a session
override void OnReceivedBroadcast(string fromAddress, string data)
Called by UnityEngine when a broadcast is received.
EventHandler< EventArgs > ConnectionStatusChanged
Event raised when connected or disconnected.
Creates, exports, and imports anchors as required.
void CreateAnchor()
If we are supposed to create the anchor for export, this is the function to call. ...
static T Instance
Returns the Singleton instance of the classes type. If no instance is found, then we search for an in...
Definition: Singleton.cs:26
void StartHosting(string SessionName)
Call to create a session
For a UWP application this should allow us to send or receive data given a server IP address...
EventHandler< EventArgs > SessionListChanged
Event raised when the list of sessions changes.