Liberi
An exergame built for kids with CP!
GameClient.cs
1 using UnityEngine;
2 using System;
3 using System.Collections;
4 using System.Collections.Generic;
5 using System.IO;
6 using System.Linq;
7 using System.Net;
8 using System.Threading;
9 using Lidgren.Network;
10 using Janus;
11 using LiberiNet;
12 
16 public class GameClient : MonoBehaviour, IActionInfoProvider
17 {
18  private class WorldServerInfo
19  {
20  public NetConnection Connection;
21  }
22 
23  private class ServerInfo
24  {
25  public NetConnection Connection;
26  public GameServerType ServerType;
27  public string MapID;
28  }
29 
30  private class ClientInfo
31  {
32  public int PeerIndex = -1;
33  public string PlayerID;
35  }
36 
37  public delegate void ConnectedToWorldServerHandler ();
38  public delegate void ConnectionToWorldServerFailedHandler ();
39  public delegate void DisconnectedFromWorldServerHandler ();
40  public delegate void ConnectedToServerHandler ();
41  public delegate void ConnectionToServerFailedHandler ();
42  public delegate void PreDisconnectFromServerHandler ();
43  public delegate void DisconnectedFromServerHandler ();
44  public delegate void ServersFoundHandler (GameServerType serverType, string mapId, IPEndPoint[] results);
45  public delegate void ServerSearchFailedHandler (GameServerType serverType, string mapId);
46  public delegate void ServerSummaryReceivedHandler (GameServerSummary serverSummary);
47  public delegate void ServerSpawnedHandler (GameServerType serverType, string mapId, IPEndPoint endPoint);
48  public delegate void ServerSpawnFailedHandler (GameServerType serverType, string mapId);
49  public delegate void PlayerFoundHandler (string playerId, GameServerType serverType, string mapId, IPEndPoint serverEndPoint);
50  public delegate void PlayerNotFoundHandler (string playerId);
51  public delegate void PlayerJoinedServerHandler (int peerIndex, PlayerProfile playerProfile);
52  public delegate void PlayerLeftServerHandler (int peerIndex, PlayerProfile playerProfile);
53  public delegate void PlayerJoinedWorldServerHandler (string playerId, string playerNickname);
54  public delegate void PlayerLeftWorldServerHandler (string playerId, string playerNickname);
55  public delegate void WorldDataReceivedHandler (UJeli worldDataPage);
56 
57 #pragma warning disable 0067
58  public event ConnectedToWorldServerHandler ConnectedToWorldServer = delegate { };
65  public event ConnectionToWorldServerFailedHandler ConnectionToWorldServerFailed = delegate { };
69  public event DisconnectedFromWorldServerHandler DisconnectedFromWorldServer = delegate { };
73  public event ConnectedToServerHandler ConnectedToServer = delegate { };
77  public event ConnectionToServerFailedHandler ConnectionToServerFailed = delegate { };
81  public event PreDisconnectFromServerHandler PreDisconnectFromServer = delegate { };
85  public event DisconnectedFromServerHandler DisconnectedFromServer = delegate { };
89  public event ServersFoundHandler ServersFound = delegate { };
93  public event ServerSearchFailedHandler ServerSearchFailed = delegate { };
97  public event ServerSummaryReceivedHandler ServerSummaryReceived = delegate { };
101  public event ServerSpawnedHandler ServerSpawned = delegate { };
105  public event ServerSpawnFailedHandler ServerSpawnFailed = delegate { };
109  public event PlayerFoundHandler PlayerFound = delegate { };
113  public event PlayerNotFoundHandler PlayerNotFound = delegate { };
117  public event PlayerJoinedServerHandler OtherPlayerJoinedServer = delegate { };
121  public event PlayerLeftServerHandler OtherPlayerLeftServer = delegate { };
125  public event PlayerJoinedWorldServerHandler OtherPlayerJoinedWorldServer = delegate{ };
129  public event PlayerLeftWorldServerHandler OtherPlayerLeftWorldServer = delegate { };
130 #pragma warning restore 0067
131 
135  public static GameClient Instance
136  {
137  get { return _instance; }
138  }
139 
143  public string ConfigBase
144  {
145  get { return _configBase; }
146  }
147 
151  public string LogsBase
152  {
153  get { return _logsBase; }
154  }
155 
159  public string ScreenshotsBase
160  {
161  get { return _screenshotsBase; }
162  }
163 
167  public string StudyLogsBase
168  {
169  get { return _studyLogsBase; }
170  }
171 
175  public ClientConfig Config
176  {
177  get { return _config; }
178  }
179 
183  public bool IsConnectedToWorldServer
184  {
185  get { return _isConnectedToWorldServer; }
186  }
187 
191  public bool IsConnectedToServer
192  {
193  get { return _isConnectedToServer; }
194  }
195 
199  public GameServerType ServerType
200  {
201  get
202  {
203  if (_server != null)
204  return _server.ServerType;
205  else return GameServerType.None;
206  }
207  }
208 
212  public string MapID
213  {
214  get
215  {
216  if (_server != null)
217  return _server.MapID;
218  else return null;
219  }
220  }
221 
225  public UJeli MapSettings
226  {
227  get { return _mapSettings; }
228  }
229 
233  public int NumPlayers
234  {
235  get { return _clientsById.Count; }
236  }
237 
241  public string[] PlayerIDs
242  {
243  get { return _clientsById.Keys.ToArray(); }
244  }
245 
249  public int[] PlayerPeerIndices
250  {
251  get { return _clientsByPeerIndex.Keys.ToArray(); }
252  }
253 
258  {
259  get
260  {
261  return (
262  from client in _clientsById.Values
263  where client.PlayerProfile != null
264  select client.PlayerProfile).ToArray();
265  }
266  }
267 
271  public string[] PlayerNicknames
272  {
273  get
274  {
275  return (
276  from client in _clientsById.Values
277  where client.PlayerProfile != null
278  select client.PlayerProfile.Basic.Nickname).ToArray();
279  }
280  }
281 
285  public string LocalPlayerID
286  {
287  get { return (_localClient != null) ? _localClient.PlayerID : _config.Network.PlayerID; }
288  }
289 
294  {
295  get { return (_localClient != null) ? _localClient.PlayerProfile : null; }
296  }
297 
298  static GameClient _instance;
299 
300  static Dictionary<NetDeliveryMethod, DeliveryMode> _netToTimelineDeliveryModes
301  = new Dictionary<NetDeliveryMethod, DeliveryMode>()
302  {
303  { NetDeliveryMethod.ReliableOrdered, DeliveryMode.ReliableOrdered },
304  { NetDeliveryMethod.ReliableUnordered, DeliveryMode.ReliableUnordered },
305  { NetDeliveryMethod.Unreliable, DeliveryMode.Unreliable },
306  };
307 
308  static Dictionary<DeliveryMode, NetDeliveryMethod> _timelineToNetDeliveryModes
309  = new Dictionary<DeliveryMode, NetDeliveryMethod>()
310  {
311  { DeliveryMode.ReliableOrdered, NetDeliveryMethod.ReliableOrdered },
312  { DeliveryMode.ReliableUnordered, NetDeliveryMethod.ReliableUnordered },
313  { DeliveryMode.Unreliable, NetDeliveryMethod.Unreliable },
314  };
315 
319  public float StatsReportInterval = 1f;
320 
321  string _configBase;
322  string _logsBase;
323  string _screenshotsBase;
324  string _studyLogsBase;
325  ClientConfig _config;
326  StreamWriter _logWriter;
327  NetPeer _netPeer;
328  WorldServerInfo _worldServer;
329  bool _isConnectedToWorldServer;
330  bool _isServerSearchCrucial;
331  ServerInfo _server;
332  bool _isServerConnectionCrucial;
333  bool _isConnectedToServer;
334  UJeli _mapSettings;
335  ClientInfo _localClient;
336  Dictionary<int, ClientInfo> _clientsByPeerIndex;
337  Dictionary<string, ClientInfo> _clientsById;
338  Dictionary<string, List<WorldDataReceivedHandler>> _worldDataRequests;
339  Dictionary<string, UJeli> _worldDataCache;
340  Dictionary<int, DateTime> _serverSummaryRequestTimes;
341  int _nextServerSummaryRequestIndex;
342 
343  List<ExtendedSpawnInfo> _postSyncObjects = new List<ExtendedSpawnInfo>();
344 
345  public struct ExtendedSpawnInfo
346  {
347  public SpawnInfo Info;
348  public int ObjectIndex;
349  public bool IsNew;
350 
351  public ExtendedSpawnInfo (SpawnInfo i, int o, bool n)
352  {
353  Info = i;
354  ObjectIndex = o;
355  IsNew = n;
356  }
357  }
358 
359  void Awake ()
360  {
361  _instance = this;
362 
363  DontDestroyOnLoad(this);
364 
365  _configBase = Path.GetFullPath(Application.dataPath + "/../Config/");
366  _logsBase = Path.GetFullPath(Application.dataPath + "/../Logs/");
367  _screenshotsBase = Path.GetFullPath(Application.dataPath + "/../Screenshots/");
368  _studyLogsBase = Path.GetFullPath(Application.dataPath + "/../Study Logs/");
369 
370  _config = new ClientConfig();
371 
372  var netPeerConfig = new NetPeerConfiguration("Liberi");
373  netPeerConfig.AcceptIncomingConnections = false;
374  netPeerConfig.EnableMessageType(NetIncomingMessageType.UnconnectedData);
375 
376  _netPeer = new NetPeer(netPeerConfig);
377 
378  _clientsByPeerIndex = new Dictionary<int, ClientInfo>();
379  _clientsById = new Dictionary<string, ClientInfo>();
380 
381  _worldDataRequests = new Dictionary<string, List<WorldDataReceivedHandler>>();
382  _worldDataCache = new Dictionary<string, UJeli>();
383 
384  _serverSummaryRequestTimes = new Dictionary<int, DateTime>();
385 
386  TimelineUtils.SetDefaultTimelineFunctions();
387  UTimelineUtils.SetDefautTimelineFunctions();
388 
389  Sync.PropagateSpawnUp += OnPropagateSpawnUp;
390  Sync.PropagateDespawnUp += OnPropagateDespawnUp;
391 
392  Sync.Initialize();
393  }
394 
395  void Start ()
396  {
397  Directory.CreateDirectory(_configBase);
398  Directory.CreateDirectory(_logsBase);
399  Directory.CreateDirectory(_screenshotsBase);
400 
401  _logWriter = File.CreateText(Path.GetFullPath(
402  string.Format("{0}Liberi_{1:yyyy-MM-dd_HH-mm-ss}.log", _logsBase, DateTime.Now)));
403  _logWriter.AutoFlush = true;
404 
405  Log("Client initializing...");
406 
407  _config.Load();
408 
409  foreach (var deviceState in _config.Devices.States)
410  {
411  if (deviceState.Value)
412  DeviceManager.Instance.EnableDevice(deviceState.Key);
413  else DeviceManager.Instance.DisableDevice(deviceState.Key);
414  }
415 
416  Controls.RegisterActionInfoProvider(ControlsAction.Back, this);
417 
418  var flags = CommandLineUtils.GetCommandLineFlags();
419 
420  if (flags.ContainsKey("playerid"))
421  _config.Network.PlayerID = flags["playerid"];
422 
423  GoToLaunchScreen(flags.ContainsKey("noupdate"));
424 
425  StartCoroutine(ReportLossyBytes());
426  }
427 
431  public void Log (string line)
432  {
433  if (_logWriter != null)
434  _logWriter.WriteLine(string.Format("[{0:HH:mm:ss}] {1}", DateTime.Now, line));
435  }
436 
437  private ClientInfo GetClient (int peerIndex)
438  {
439  ClientInfo client = null;
440  _clientsByPeerIndex.TryGetValue(peerIndex, out client);
441  return client;
442  }
443 
444  private ClientInfo GetClient (string playerId)
445  {
446  ClientInfo client = null;
447  _clientsById.TryGetValue(playerId, out client);
448  return client;
449  }
450 
454  public int GetPlayerPeerIndex (string playerId)
455  {
456  var client = GetClient(playerId);
457 
458  if (client != null)
459  return client.PeerIndex;
460  else return -1;
461  }
462 
466  public string GetPlayerID (int peerIndex)
467  {
468  var client = GetClient(peerIndex);
469 
470  if (client != null)
471  return client.PlayerID;
472  else return null;
473  }
474 
478  public PlayerProfile GetPlayerProfile (string playerId)
479  {
480  var client = GetClient(playerId);
481 
482  if (client != null)
483  return client.PlayerProfile;
484  else return null;
485  }
486 
490  public PlayerProfile GetPlayerProfile (int peerIndex)
491  {
492  var client = GetClient(peerIndex);
493 
494  if (client != null)
495  return client.PlayerProfile;
496  else return null;
497  }
498 
503  public void GoToLaunchScreen (bool upToDate)
504  {
505  LaunchScreen.UpToDate = upToDate;
506  Application.LoadLevel("launch");
507  }
508 
512  public void ConnectToWorldServer ()
513  {
514  Log("Starting network...");
515 
516  try { _netPeer.Start(); }
517  catch { }
518 
519  if (_netPeer.Status != NetPeerStatus.Running)
520  {
521  Log("Failed to start network.");
522  DisconnectFromWorldServer("error.net_start_fail");
523  return;
524  }
525 
526  Log("Network started.");
527 
528  StatusOverlay.ShowStatus(Localizer.GetString("status.searching"));
529 
530  IPEndPoint worldEndPoint = null;
531 
532  if (string.IsNullOrEmpty(_config.Network.WorldID))
533  {
534  _config.Network.WorldID = "localhost";
535  _config.Network.Save();
536  }
537 
538  IPAddress ipAddress = null;
539  IPAddress.TryParse(_config.Network.WorldID, out ipAddress);
540 
541  Log("Searching for world server: " + _config.Network.WorldID);
542 
543  if (_config.Network.WorldID == "localhost")
544  worldEndPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 34443);
545  else if (ipAddress != null)
546  worldEndPoint = new IPEndPoint(ipAddress, 34443);
547  else worldEndPoint = WorldNetUtils.GetWorldEndPoint(_config.Network.WorldID);
548 
549  if (worldEndPoint == null)
550  {
551  Log("Failed to find world server.");
552  DisconnectFromWorldServer("error.world_not_found");
553  return;
554  }
555 
556  Log("World server found.");
557 
558  var localHail = _netPeer.CreateMessage();
559  localHail.Write((byte)WorldServerMessageType.RegisterClient);
560  localHail.Write(_config.Network.PlayerID);
561 
562  StatusOverlay.ShowStatus(Localizer.GetString("status.connecting"));
563 
564  Log("Connecting to world server at: " + worldEndPoint);
565 
566  _worldServer = new WorldServerInfo();
567  _worldServer.Connection = _netPeer.Connect(worldEndPoint, localHail);
568  _worldServer.Connection.Tag = _worldServer;
569  }
570 
575  public void DisconnectFromWorldServer (string error = "")
576  {
577  if (_isConnectedToServer)
579 
580  _localClient = null;
581  _isConnectedToWorldServer = false;
582  _worldServer = null;
583 
584  if (_netPeer.Status != NetPeerStatus.NotRunning && _netPeer.Status != NetPeerStatus.ShutdownRequested)
585  {
586  Log("Stopping network...");
587 
588  _netPeer.Shutdown(error);
589 
590  Log("Network stopped.");
591  }
592 
593  if (error != "")
595 
596  GoToLaunchScreen(false);
597  }
598 
607  public void FindServers (GameServerType serverType, string mapId, bool isCrucial)
608  {
609  Log("Searching for servers. Map: " + mapId);
610 
611  StatusOverlay.ShowStatus(Localizer.GetString("status.searching"));
612 
613  var searchMsg = _netPeer.CreateMessage();
614  searchMsg.Write((byte)WorldServerMessageType.FindServers);
615  searchMsg.Write(serverType.ToString().ToLower());
616  searchMsg.Write(mapId);
617 
618  _isServerSearchCrucial = isCrucial;
619 
620  _worldServer.Connection.SendMessage(searchMsg, NetDeliveryMethod.ReliableOrdered, 0);
621  }
622 
626  public void RequestServerSummary (IPEndPoint serverEndPoint)
627  {
628  var requestMsg = _netPeer.CreateMessage();
629  requestMsg.Write((byte)ServerMessageType.Custom);
630  requestMsg.Write((byte)CustomServerMessageType.SummaryRequest);
631  requestMsg.Write(_nextServerSummaryRequestIndex);
632 
633  _netPeer.SendUnconnectedMessage(requestMsg, serverEndPoint);
634 
635  _serverSummaryRequestTimes[_nextServerSummaryRequestIndex] = DateTime.Now;
636  _nextServerSummaryRequestIndex++;
637  }
638 
644  public void RequestServerSpawn (GameServerType serverType, string mapId)
645  {
646  var requestMsg = _netPeer.CreateMessage();
647  requestMsg.Write((byte)WorldServerMessageType.SpawnServer);
648  requestMsg.Write(serverType.ToString().ToLower());
649  requestMsg.Write(mapId);
650 
651  _worldServer.Connection.SendMessage(requestMsg, NetDeliveryMethod.ReliableOrdered, 0);
652  }
653 
663  public void ConnectToServer (IPEndPoint serverEndPoint, GameServerType serverType, string mapId, bool isCrucial)
664  {
665  if (_isConnectedToServer)
667 
668  var localHail = _netPeer.CreateMessage();
669  localHail.Write(_localClient.PlayerProfile.PlayerID);
670 
671  _server = new ServerInfo()
672  {
673  ServerType = serverType,
674  MapID = mapId
675  };
676 
677  _isServerConnectionCrucial = isCrucial;
678 
679  Log("Connecting to server at: " + serverEndPoint);
680 
681  StatusOverlay.ShowStatus(Localizer.GetString("status.connecting"));
682 
683  _server.Connection = _netPeer.Connect(serverEndPoint, localHail);
684  _server.Connection.Tag = _server;
685  }
686 
690  public void DisconnectFromServer ()
691  {
692  if (_server == null)
693  return;
694 
695  if (PreDisconnectFromServer != null)
697 
698  Log("Unsyncing from server...");
699 
700  Sync.UnsyncClient();
701 
702  Log("Unsynced from server.");
703 
704  if (_server.Connection.Status == NetConnectionStatus.Connected)
705  {
706  Log("Disconnecting from server...");
707 
708  _server.Connection.Disconnect("");
709 
710  Log("Disconnected from server.");
711  }
712 
713  _clientsByPeerIndex.Clear();
714  _clientsById.Clear();
715 
716  _isConnectedToServer = false;
717  _server = null;
718  }
719 
726  public void PullWorldData (string pageName, WorldDataReceivedHandler callback, bool useCache = false)
727  {
728  if (useCache)
729  {
730  var cachedDataPage = GetCachedWorldData(pageName);
731 
732  if (cachedDataPage != null && callback != null)
733  {
734  callback(cachedDataPage);
735  return;
736  }
737  }
738 
739  Log("Pulling world data page: " + pageName);
740 
741  List<WorldDataReceivedHandler> callbacksByPage = null;
742 
743  if (!_worldDataRequests.TryGetValue(pageName, out callbacksByPage))
744  {
745  callbacksByPage = new List<WorldDataReceivedHandler>();
746  _worldDataRequests.Add(pageName, callbacksByPage);
747  }
748 
749  callbacksByPage.Add(callback);
750 
751  var worldDataPullMsg = _netPeer.CreateMessage();
752  worldDataPullMsg.Write((byte)WorldServerMessageType.PullWorldData);
753  worldDataPullMsg.Write(pageName);
754 
755  _worldServer.Connection.SendMessage(worldDataPullMsg, NetDeliveryMethod.ReliableOrdered, 0);
756  }
757 
758  public string GetActionCaption (ControlsAction actionType)
759  {
760  if (actionType == ControlsAction.Back)
761  {
762  return Localizer.GetString("caption.quit_game");
763  }
764 
765  return "";
766  }
767 
768  public bool IsActionEnabled (ControlsAction actionType)
769  {
770  return true;
771  }
772 
773  private void Quit ()
774  {
776 
777  if (DisconnectedFromServer != null)
779 
780  if (_isServerConnectionCrucial)
781  {
782 #if UNITY_EDITOR
783  UnityEditor.EditorApplication.isPlaying = false;
784 #else
785  Application.Quit();
786 #endif
787  }
788  else FindServers(GameServerType.Zone, _localClient.PlayerProfile.Location.LastZoneMapID, true);
789  }
790 
795  public UJeli GetCachedWorldData (string pageName)
796  {
797  UJeli dataPage = null;
798  _worldDataCache.TryGetValue(pageName, out dataPage);
799  return dataPage;
800  }
801 
806  public bool ToggleFullScreen ()
807  {
808  bool newFullScreen = !_config.Video.FullScreen;
809  Screen.SetResolution(_config.Video.Width, _config.Video.Height, newFullScreen);
810 
811  _config.Video.FullScreen = newFullScreen;
812  _config.Video.Save();
813 
814  return newFullScreen;
815  }
816 
820  public void SaveScreenshot ()
821  {
822  int numScreenshotsThisSecond = 1;
823  string screenshotPath = null;
824 
825  do
826  {
827  screenshotPath = string.Format("{0}Screenshot_{1:yyyy-MM-dd_HH-mm-ss}_{2:00}.png",
828  _screenshotsBase, DateTime.Now, numScreenshotsThisSecond);
829 
830  numScreenshotsThisSecond++;
831  }
832  while (File.Exists(screenshotPath));
833 
834  Application.CaptureScreenshot(screenshotPath);
835  }
836 
837  private void LoadAndSyncMap (string mapId, int peerIndex)
838  {
839  StopCoroutine("LoadAndSyncMapAsync");
840  StartCoroutine(LoadAndSyncMapAsync(mapId, peerIndex));
841  }
842 
843  private IEnumerator LoadAndSyncMapAsync (string mapId, int peerIndex)
844  {
845  Log("Pulling map settings...");
846 
847  PullWorldData(MapID + "_settings", OnMapSettingsReceived);
848 
849  float settingsWaitTime = 0f;
850 
851  while (_mapSettings == null)
852  {
853  settingsWaitTime += .1f;
854 
855  if (settingsWaitTime >= 10f)
856  {
857  DisconnectFromWorldServer("error.map_settings_fail");
858  yield break;
859  }
860 
861  yield return new WaitForSeconds(.1f);
862  }
863 
864  Log("Map settings received.");
865  Log("Loading map: " + mapId);
866 
867  StatusOverlay.ShowStatus(Localizer.GetString("status.loading"));
868 
869  yield return Application.LoadLevelAsync(mapId);
870 
871  Log("Map loaded.");
872 
873  if (_server == null || _server.Connection.Status != NetConnectionStatus.Connected)
874  yield break;
875 
876  StatusOverlay.ShowStatus(Localizer.GetString("status.syncing"));
877 
878  Log("Syncing to server...");
879 
880  Sync.BeginSyncClient(peerIndex);
881 
882  var syncMessage = _netPeer.CreateMessage();
883  syncMessage.Write((byte)ServerMessageType.Custom);
884  syncMessage.Write((byte)CustomServerMessageType.SyncWithClient);
885 
886  _server.Connection.SendMessage(syncMessage, NetDeliveryMethod.ReliableOrdered, 0);
887 
888  while (!Sync.IsMapSynced)
889  {
890  if (_server == null || _server.Connection.Status != NetConnectionStatus.Connected)
891  yield break;
892 
893  yield return null;
894  }
895 
896  foreach (var obj in _postSyncObjects)
897  {
898  if (Sync.GetObject(obj.ObjectIndex) == null)
899  {
900  try {Sync.ProcessPropagatedDownSpawn(obj.Info, obj.ObjectIndex, obj.IsNew);}
901 
902  catch (ArgumentException e)
903  {
904  Debug.LogWarning(e.Message + "\n" + obj.Info.Prefab.name + ", " + obj.ObjectIndex +
905  " was skipped when spawning postSyncObjects due to it haveing already been spawned in an edge case.");
906  }
907  }
908  }
909 
910  _postSyncObjects.Clear();
911 
912  Log("Synced to server.");
913 
915 
916  yield break;
917  }
918 
919  internal void SendPlayerProfileOperation (GameMessage op)
920  {
921  var opMsg = _netPeer.CreateMessage();
922  opMsg.Write((byte)CustomServerMessageType.PlayerProfileOperation);
923  opMsg.Write(Game.LocalPeerIndex);
924  opMsg.Write(op.Data);
925 
926  _worldServer.Connection.SendMessage(opMsg, NetDeliveryMethod.ReliableOrdered, 0);
927  }
928 
929  void Update ()
930  {
931  UpdateScreenshot();
932  UpdateNetwork();
933 
934 #if UNITY_EDITOR
935  if (Input.GetKey(KeyCode.LeftControl) && Input.GetKeyDown(KeyCode.Q))
936  {
938  UnityEditor.EditorApplication.isPlaying = false;
939  }
940 #endif
941  if (Controls.GetActionHoldTime(ControlsAction.Back) > 3.0f)
942  {
943  Controls.ResetHoldTime(ControlsAction.Back);
944  Quit();
945  }
946  }
947 
948  private void UpdateScreenshot ()
949  {
950  if (Input.GetKeyDown(_config.Controls.TakeScreenshot))
951  SaveScreenshot();
952  }
953 
954  int _lossyBytes = 0;
955 
956  IEnumerator ReportLossyBytes ()
957  {
958  float t = 0;
959 
960  while (true)
961  {
962  yield return new WaitForSeconds(1.0f);
963  t += 1.0f;
964 
965  DebugManager.Log((float)_lossyBytes/t + " bytes/sec of lossy data.");
966  }
967  }
968 
969  private void UpdateNetwork ()
970  {
971  if (_netPeer.Status != NetPeerStatus.Running)
972  return;
973 
974  if (Sync.IsMapSynced)
975  {
976  Sync.Step();
977 
978  foreach (var timelineMsg in Sync.TimelineManager.GetOutgoingMessages())
979  {
980  var timelineNetMsg = _netPeer.CreateMessage();
981  timelineNetMsg.Write((byte)timelineMsg.MessageType);
982  timelineNetMsg.Write(timelineMsg.Data);
983 
984  _server.Connection.SendMessage(
985  timelineNetMsg,
986  _timelineToNetDeliveryModes[timelineMsg.DeliveryMode],
987  0);
988  }
989  }
990 
991  var messages = new List<NetIncomingMessage>();
992  _netPeer.ReadMessages(messages);
993 
994  foreach (var msg in messages)
995  {
996 #if !UNITY_EDITOR
997  try
998  {
999 #endif
1000  if (msg.DeliveryMethod == NetDeliveryMethod.Unreliable)
1001  _lossyBytes += msg.LengthBytes;
1002 
1003  ProcessNetMessage(msg);
1004 #if !UNITY_EDITOR
1005  }
1006  catch (Exception e)
1007  {
1008  Log(string.Format("Network message exception. Message Type: {0}, Exception Type: {1}",
1009  msg.MessageType, e.GetType()));
1010  }
1011 #endif
1012  }
1013 
1014  _netPeer.Recycle(messages);
1015  }
1016 
1017  private void ProcessNetMessage (NetIncomingMessage msg)
1018  {
1019  if (msg.MessageType == NetIncomingMessageType.StatusChanged)
1020  {
1021  var newStatus = (NetConnectionStatus)msg.ReadByte();
1022 
1023  if (newStatus == NetConnectionStatus.Connected)
1024  {
1025  if (msg.SenderConnection.Tag == _server && _server != null)
1026  {
1027  var remoteHail = msg.SenderConnection.RemoteHailMessage;
1028 
1029  _localClient.PeerIndex = remoteHail.ReadInt32();
1030 
1031  _clientsByPeerIndex.Add(_localClient.PeerIndex, _localClient);
1032  _clientsById.Add(_localClient.PlayerID, _localClient);
1033 
1034  _isConnectedToServer = true;
1035 
1036  Log(string.Format("Connected to server. Type: {0}, Map: {1}",
1037  _server.ServerType, _server.MapID));
1038 
1039  Log("Peer index assigned: " + _localClient.PeerIndex);
1040 
1041  if (ConnectedToServer != null)
1043 
1044  LoadAndSyncMap(_server.MapID, _localClient.PeerIndex);
1045  }
1046  }
1047  else if (newStatus == NetConnectionStatus.Disconnected)
1048  {
1049  string reason = msg.ReadString();
1050 
1051  if (msg.SenderConnection.Tag == _worldServer && _worldServer != null)
1052  {
1053  if (_isConnectedToWorldServer)
1054  {
1055  Log("Disconnected from world server.");
1056  DisconnectFromWorldServer("error.world_disconnect");
1057 
1058  if (DisconnectedFromWorldServer != null)
1060  }
1061  else
1062  {
1063  Log("Failed to connect to world server.");
1064 
1065  if (reason == "error.duplicate_player" ||
1066  reason == "error.daily_limit_reached")
1067  {
1068  DisconnectFromWorldServer(reason);
1069  }
1070  else DisconnectFromWorldServer("error.world_connect_fail");
1071 
1072  if (ConnectionToWorldServerFailed != null)
1074  }
1075  }
1076  else if (msg.SenderConnection.Tag == _server && _server != null)
1077  {
1078  if (_isConnectedToServer)
1079  {
1080  Log("Disconnected from server.");
1082 
1083  if (DisconnectedFromServer != null)
1085 
1086  if (_isServerConnectionCrucial)
1087  {
1088  DisconnectFromWorldServer("error.server_disconnect");
1089  }
1090  else FindServers(GameServerType.Zone, _localClient.PlayerProfile.Location.LastZoneMapID, true);
1091  }
1092  else
1093  {
1094  Log("Failed to connect to server.");
1096 
1097  if (ConnectionToServerFailed != null)
1099 
1100  if (_isServerConnectionCrucial)
1101  {
1102  if (reason == "error.duplicate_player")
1103  DisconnectFromWorldServer(reason);
1104  else DisconnectFromWorldServer("error.server_connect_fail");
1105  }
1106  else FindServers(GameServerType.Zone, _localClient.PlayerProfile.Location.LastZoneMapID, true);
1107  }
1108  }
1109  }
1110  }
1111  else if (msg.MessageType == NetIncomingMessageType.Data)
1112  {
1113  byte messageTypeByte = msg.ReadByte();
1114 
1115  if (messageTypeByte >= (byte)TimelineMessageType.ManagerMessageBase)
1116  {
1117  if (!_isConnectedToServer)
1118  return;
1119 
1120  var timelineMessageType = (TimelineMessageType)messageTypeByte;
1121  var timelineMsg = new TimelineMessage(
1122  timelineMessageType,
1123  msg.ReadBytes(msg.LengthBytes - msg.PositionInBytes),
1124  _netToTimelineDeliveryModes[msg.DeliveryMethod]);
1125 
1126  Sync.TimelineManager.ProcessIncomingMessage(timelineMsg);
1127  }
1128  else
1129  {
1130  var clientMessageType = (ClientMessageType)messageTypeByte;
1131 
1132  if (clientMessageType == ClientMessageType.ClientInitialization)
1133  {
1134  _isConnectedToWorldServer = true;
1135 
1136  Log("Connected to world server.");
1137 
1138  UJeli profileJeli = UJeli.Parse(msg.ReadString());
1139  var localPlayerProfile = new PlayerProfile(_config.Network.PlayerID, profileJeli);
1140 
1141  _localClient = new ClientInfo()
1142  {
1143  PlayerID = _config.Network.PlayerID,
1144  PlayerProfile = localPlayerProfile
1145  };
1146 
1147  Log(string.Format("Received player profile. ID: {0}, Nickname: {1}",
1148  _localClient.PlayerID, localPlayerProfile.Basic.Nickname));
1149 
1150  if (ConnectedToWorldServer != null)
1152 
1153  if (!string.IsNullOrEmpty(_localClient.PlayerProfile.Location.LastZoneMapID))
1154  FindServers(GameServerType.Zone, _localClient.PlayerProfile.Location.LastZoneMapID, true);
1155  }
1156  else if (clientMessageType == ClientMessageType.ServersFound)
1157  {
1158  GameServerType serverType = (GameServerType)Enum.Parse(typeof(GameServerType), msg.ReadString(), true);
1159  string mapId = msg.ReadString();
1160  int numResults = msg.ReadInt32();
1161 
1162  Log(string.Format("{0} server(s) found.", numResults));
1163 
1164  if (numResults != 0)
1165  {
1166  IPEndPoint[] results = new IPEndPoint[numResults];
1167 
1168  for (int i = 0; i < numResults; i++)
1169  {
1170  results[i] = msg.ReadIPEndPoint();
1171  }
1172 
1173  if (_server != null)
1174  {
1175  if (_server.ServerType == GameServerType.Minigame && serverType == GameServerType.Zone)
1176  {
1177  // If we're currently in a minigame, and we got a zone server search result,
1178  // then this is probably the zone the player needs to return to,
1179  // so we disconnect from our minigame server and connect to the zone server.
1180  ConnectToServer(results[0], GameServerType.Zone, mapId, true);
1181  return;
1182  }
1183  }
1184  else
1185  {
1186  if (serverType == GameServerType.Zone)
1187  {
1188  // If we're not connected to a server, and we got a zone server search result,
1189  // then this is probably the zone the player needs to spawn in, so we connect to it.
1190  ConnectToServer(results[0], GameServerType.Zone, mapId, true);
1191  return;
1192  }
1193  }
1194 
1195  if (ServersFound != null)
1196  ServersFound(serverType, mapId, results);
1197  }
1198  else
1199  {
1200  if (ServerSearchFailed != null)
1201  ServerSearchFailed(serverType, mapId);
1202 
1203  if (_isServerSearchCrucial)
1204  DisconnectFromWorldServer("error.server_not_found");
1205  }
1206  }
1207  else if (clientMessageType == ClientMessageType.ServerSpawned)
1208  {
1209  GameServerType serverType = (GameServerType)Enum.Parse(typeof(GameServerType), msg.ReadString(), true);
1210  string mapId = msg.ReadString();
1211  IPEndPoint endPoint = msg.ReadIPEndPoint();
1212 
1213  if (ServerSpawned != null)
1214  ServerSpawned(serverType, mapId, endPoint);
1215  }
1216  else if (clientMessageType == ClientMessageType.ServerSpawnFailed)
1217  {
1218  GameServerType serverType = (GameServerType)msg.ReadByte();
1219  string mapId = msg.ReadString();
1220 
1221  if (ServerSpawnFailed != null)
1222  ServerSpawnFailed(serverType, mapId);
1223  }
1224  else if (clientMessageType == ClientMessageType.PlayerFound)
1225  {
1226  string playerId = msg.ReadString();
1227  bool found = msg.ReadBoolean();
1228 
1229  if (found)
1230  {
1231  GameServerType serverType = (GameServerType)msg.ReadByte();
1232  string mapId = msg.ReadString();
1233  IPEndPoint serverEndPoint = msg.ReadIPEndPoint();
1234 
1235  if (PlayerFound != null)
1236  PlayerFound(playerId, serverType, mapId, serverEndPoint);
1237  }
1238  else
1239  {
1240  if (PlayerNotFound != null)
1241  PlayerNotFound(playerId);
1242  }
1243  }
1244  else if (clientMessageType == ClientMessageType.Custom)
1245  {
1246  CustomClientMessageType customClientMessageType = (CustomClientMessageType)msg.ReadByte();
1247 
1248  if (customClientMessageType == CustomClientMessageType.SyncedToServer)
1249  {
1250  Sync.FinishSyncClient();
1251  UpdateNetwork();
1252 
1253  var syncFinishedMsg = _netPeer.CreateMessage();
1254  syncFinishedMsg.Write((byte)ServerMessageType.Custom);
1255  syncFinishedMsg.Write((byte)CustomServerMessageType.ClientFinishedSyncing);
1256 
1257  _server.Connection.SendMessage(syncFinishedMsg, NetDeliveryMethod.ReliableOrdered, 0);
1258  }
1259  else if (customClientMessageType == CustomClientMessageType.ExistingPlayers)
1260  {
1261  int numExistingPlayers = msg.ReadInt32();
1262 
1263  for (int i = 0; i < numExistingPlayers; i++)
1264  {
1265  int peerIndex = msg.ReadInt32();
1266  string playerId = msg.ReadString();
1267  var playerProfile = new PlayerProfile(playerId, UJeli.Parse(msg.ReadString()));
1268 
1269  if (_clientsByPeerIndex.ContainsKey(peerIndex))
1270  return;
1271 
1272  var otherClient = new ClientInfo()
1273  {
1274  PeerIndex = peerIndex,
1275  PlayerID = playerId,
1276  PlayerProfile = playerProfile
1277  };
1278 
1279  _clientsByPeerIndex.Add(peerIndex, otherClient);
1280  _clientsById.Add(playerId, otherClient);
1281 
1282  Log(string.Format("Received existing player info. Index: {0}, ID: {1}, Nickname: {2}",
1283  peerIndex, playerId, playerProfile.Basic.Nickname));
1284  }
1285  }
1286  else if (customClientMessageType == CustomClientMessageType.PlayerProfileOperation)
1287  {
1288  int peerIndex = msg.ReadInt32();
1289 
1290  var profile = GetPlayerProfile(peerIndex);
1291 
1292  if (profile == null)
1293  return;
1294 
1295  var profileOperation = new GameMessage();
1296  profileOperation.Write(msg.ReadBytes(msg.LengthBytes - msg.PositionInBytes));
1297 
1298  profile.ProcessIncomingOperation(profileOperation);
1299  }
1300  else if (customClientMessageType == CustomClientMessageType.SpawnObject)
1301  {
1302  var spawnInfo = new SpawnInfo();
1303  spawnInfo.ReadFrom(msg);
1304  int objectIndex = msg.ReadInt32();
1305 
1306  if (!Sync.IsMapSynced)
1307  {
1308  _postSyncObjects.Add(new ExtendedSpawnInfo(spawnInfo, objectIndex, true));
1309  return;
1310  }
1311 
1312  try {Sync.ProcessPropagatedDownSpawn(spawnInfo, objectIndex, true);}
1313 
1314  catch (ArgumentException e)
1315  {
1316  Debug.LogError(e.Message);
1317  Debug.Log(spawnInfo.Prefab.name + ", " + objectIndex);
1318  }
1319  }
1320  else if (customClientMessageType == CustomClientMessageType.SpawnExistingObject)
1321  {
1322  bool hasSpawnInfo = msg.ReadBoolean();
1323  SpawnInfo spawnInfo = null;
1324 
1325  if (hasSpawnInfo)
1326  {
1327  spawnInfo = new SpawnInfo();
1328  spawnInfo.ReadFrom(msg);
1329  }
1330 
1331  int objectIndex = msg.ReadInt32();
1332 
1333  try {Sync.ProcessPropagatedDownSpawn(spawnInfo, objectIndex, false);}
1334 
1335  catch (ArgumentException e)
1336  {
1337  Debug.LogWarning(e.Message);
1338  Debug.Log(spawnInfo + ", " + objectIndex);
1339  }
1340  }
1341  else if (customClientMessageType == CustomClientMessageType.ObjectSpawnRequestResponse)
1342  {
1343  int requestIndex = msg.ReadInt32();
1344  int objectIndex = msg.ReadInt32();
1345 
1346  Sync.ProcessSpawnRequestResponse(requestIndex, objectIndex);
1347  }
1348  else if (customClientMessageType == CustomClientMessageType.DespawnObject)
1349  {
1350  int objectIndex = msg.ReadInt32();
1351 
1352  Sync.ProcessPropagatedDownDespawn(objectIndex);
1353  }
1354  else if (customClientMessageType == CustomClientMessageType.PlayerJoinedServer)
1355  {
1356  int peerIndex = msg.ReadInt32();
1357  string playerId = msg.ReadString();
1358  var playerProfile = new PlayerProfile(playerId, UJeli.Parse(msg.ReadString()));
1359 
1360  var client = new ClientInfo()
1361  {
1362  PeerIndex = peerIndex,
1363  PlayerID = playerId,
1364  PlayerProfile = playerProfile
1365  };
1366 
1367  _clientsByPeerIndex.Add(peerIndex, client);
1368  _clientsById.Add(playerId, client);
1369 
1370  if (OtherPlayerJoinedServer != null)
1371  OtherPlayerJoinedServer(peerIndex, playerProfile);
1372  }
1373  else if (customClientMessageType == CustomClientMessageType.PlayerLeftServer)
1374  {
1375  int peerIndex = msg.ReadInt32();
1376 
1377  ClientInfo client = null;
1378  _clientsByPeerIndex.TryGetValue(peerIndex, out client);
1379 
1380  if (client != null)
1381  {
1382  _clientsByPeerIndex.Remove(peerIndex);
1383  _clientsById.Remove(client.PlayerID);
1384  }
1385 
1386  if (OtherPlayerLeftServer != null)
1387  OtherPlayerLeftServer(peerIndex, client.PlayerProfile);
1388  }
1389  }
1390  else if (clientMessageType == ClientMessageType.WorldData)
1391  {
1392  string pageName = msg.ReadString();
1393  var worldDataPage = UJeli.Parse(msg.ReadString());
1394  worldDataPage.Name = pageName;
1395 
1396  Log("Received world data page: " + pageName);
1397 
1398  _worldDataCache[pageName] = worldDataPage;
1399 
1400  List<WorldDataReceivedHandler> callbacksByPage = null;
1401 
1402  if (_worldDataRequests.TryGetValue(pageName, out callbacksByPage))
1403  {
1404  if (callbacksByPage.Count > 0)
1405  {
1406  callbacksByPage[0](worldDataPage);
1407  callbacksByPage.RemoveAt(0);
1408  }
1409  }
1410  }
1411  }
1412  }
1413  else if (msg.MessageType == NetIncomingMessageType.UnconnectedData)
1414  {
1415  var clientMessageType = (ClientMessageType)msg.ReadByte();
1416 
1417  if (clientMessageType == ClientMessageType.Custom)
1418  {
1419  var customClientMessageType = (CustomClientMessageType)msg.ReadByte();
1420 
1421  if (customClientMessageType == CustomClientMessageType.ServerSummary)
1422  {
1423  var serverSummary = new GameServerSummary();
1424 
1425  int requestIndex = msg.ReadInt32();
1426 
1427  if (!_serverSummaryRequestTimes.ContainsKey(requestIndex))
1428  return;
1429 
1430  serverSummary.EndPoint = msg.SenderEndPoint;
1431  serverSummary.RTT = (float)DateTime.Now.Subtract(_serverSummaryRequestTimes[requestIndex]).TotalSeconds;
1432  serverSummary.ServerType = (GameServerType)msg.ReadByte();
1433  serverSummary.MapID = msg.ReadString();
1434  serverSummary.MaxPlayers = msg.ReadInt32();
1435  serverSummary.PlayerProfiles = new PlayerProfile[msg.ReadInt32()];
1436 
1437  for (int i = 0; i < serverSummary.PlayerProfiles.Length; i++)
1438  {
1439  // TODO: Server Summaries should include player IDs somehow.
1440  serverSummary.PlayerProfiles[i] = new PlayerProfile(msg.ReadString(), UJeli.Parse(msg.ReadString()));
1441  }
1442 
1443  if (ServerSummaryReceived != null)
1444  ServerSummaryReceived(serverSummary);
1445 
1446  _serverSummaryRequestTimes.Remove(requestIndex);
1447  }
1448  }
1449  }
1450  }
1451 
1452  private void OnMapSettingsReceived (UJeli mapSettings)
1453  {
1454  _mapSettings = mapSettings;
1455 
1456  if (_mapSettings.HasChild("SpawnDetailsTemplates"))
1457  {
1458  var spawnDetailsTemplatesJeli = _mapSettings["SpawnDetailsTemplates"];
1459 
1460  foreach (var templateJeli in spawnDetailsTemplatesJeli.Children)
1461  {
1462  Sync.SetSpawnDetailsTemplate(templateJeli.Name, templateJeli);
1463  }
1464  }
1465  }
1466 
1467  private void OnPropagateSpawnUp (int requestIndex, SpawnInfo spawnInfo)
1468  {
1469  var spawnMsg = _netPeer.CreateMessage();
1470  spawnMsg.Write((byte)ServerMessageType.Custom);
1471  spawnMsg.Write((byte)CustomServerMessageType.SpawnObject);
1472  spawnMsg.Write(requestIndex);
1473  spawnInfo.WriteTo(spawnMsg);
1474 
1475  _server.Connection.SendMessage(spawnMsg, NetDeliveryMethod.ReliableOrdered, 0);
1476  }
1477 
1478  private void OnPropagateDespawnUp (int objectIndex)
1479  {
1480  StartCoroutine(PropagateDespawnUpAsync(objectIndex));
1481  }
1482 
1483  private IEnumerator PropagateDespawnUpAsync (int objectIndex)
1484  {
1485  yield return null;
1486  yield return null;
1487 
1488  var despawnMsg = _netPeer.CreateMessage();
1489  despawnMsg.Write((byte)ServerMessageType.Custom);
1490  despawnMsg.Write((byte)CustomServerMessageType.DespawnObject);
1491  despawnMsg.Write(objectIndex);
1492 
1493  _server.Connection.SendMessage(despawnMsg, NetDeliveryMethod.ReliableOrdered, 0);
1494  }
1495 
1496  void OnDestroy ()
1497  {
1500 
1501  Log("Client shutting down...");
1502 
1503  _logWriter.Dispose();
1504 
1505  _instance = null;
1506  }
1507 }
PlayerProfile[] PlayerProfiles
Gets an array containing the profiles of all players connected to the current server.
Definition: GameClient.cs:258
static string GetString(string key, SystemLanguage language=SystemLanguage.Unknown)
Gets the localized string for the given string key.
Definition: Localizer.cs:55
PlayerLeftWorldServerHandler OtherPlayerLeftWorldServer
Event fired when another player leaves the world server.
Definition: GameClient.cs:129
PlayerProfile GetPlayerProfile(string playerId)
Get the profile of the player with the given ID.
Definition: GameClient.cs:478
ServerSpawnFailedHandler ServerSpawnFailed
Event fired when a requested server spawn fails.
Definition: GameClient.cs:105
void DisconnectFromWorldServer(string error="")
Disconnect from the world server.
Definition: GameClient.cs:575
ServersFoundHandler ServersFound
Event fired when a server search returns results.
Definition: GameClient.cs:89
static void ShowError(string error)
Show the overlay with a given error message.
void PullWorldData(string pageName, WorldDataReceivedHandler callback, bool useCache=false)
Requests a specific page of world data from the world server.
Definition: GameClient.cs:726
bool IsConnectedToWorldServer
Gets whether or not this client is connected to the world server.
Definition: GameClient.cs:184
string[] PlayerNicknames
Gets an array containing the nicknames of all connected players.
Definition: GameClient.cs:272
Game client launch screen.
Definition: LaunchScreen.cs:12
ServerSearchFailedHandler ServerSearchFailed
Event fired when a server search fails.
Definition: GameClient.cs:93
PlayerNotFoundHandler PlayerNotFound
Event fired when a player search fails.
Definition: GameClient.cs:113
void RequestServerSpawn(GameServerType serverType, string mapId)
Sends a server spawn request to the world server.
Definition: GameClient.cs:644
string[] PlayerIDs
Gets an array containing the IDs of all players connected to the current server.
Definition: GameClient.cs:242
ConnectedToServerHandler ConnectedToServer
Event fired when the game client successfully connects to a server.
Definition: GameClient.cs:73
PlayerFoundHandler PlayerFound
Event fired when a player search is successful.
Definition: GameClient.cs:109
Localization manager.
Definition: Localizer.cs:9
bool IsActionEnabled(ControlsAction actionType)
Gets whether or not the given action is enabled.
Definition: GameClient.cs:768
GameServerType ServerType
Gets the type of server we are connected to, if any.
Definition: GameClient.cs:200
string GetActionCaption(ControlsAction actionType)
Gets the caption to use for the given action.
Definition: GameClient.cs:758
int NumPlayers
Gets the number of players connected to the current server.
Definition: GameClient.cs:234
float StatsReportInterval
The interval at which to report local player statistics to the world server.
Definition: GameClient.cs:319
UJeli GetCachedWorldData(string pageName)
Returns a cached copy of a previously fetched world data page.
Definition: GameClient.cs:795
int[] PlayerPeerIndices
Gets an array containing the peer indices of all players connected to the current server...
Definition: GameClient.cs:250
PreDisconnectFromServerHandler PreDisconnectFromServer
Event fired before the server disconnection code is run (before profiles are remove/unsync occurs)...
Definition: GameClient.cs:81
string ScreenshotsBase
Gets the base path for screenshots.
Definition: GameClient.cs:160
static float GetActionHoldTime(ControlsAction action)
Returns the amount of time the given action has been held down.
Definition: Controls.cs:210
An overlay for displaying game status on the game client.
static DeviceManager Instance
Gets the sole instance of the device manager.
void Log(string line)
Write one line to the client log. Log entries are automatically timestamped.
Definition: GameClient.cs:431
void ConnectToWorldServer()
Connect to the world server specified in the network configuration.
Definition: GameClient.cs:512
static bool IsMapSynced
Gets whether or not the map on this peer is synced to the canonical version on the network...
Definition: Sync.Static.cs:70
void RequestServerSummary(IPEndPoint serverEndPoint)
Requests a summary from the server at the given end point.
Definition: GameClient.cs:626
DisconnectedFromWorldServerHandler DisconnectedFromWorldServer
Event fired when the game client is disconnected from the world server.
Definition: GameClient.cs:69
static void ShowStatus(string status)
Show the overlay with a given status message.
string LocalPlayerID
Gets the player ID of the local client.
Definition: GameClient.cs:286
ServerSummaryReceivedHandler ServerSummaryReceived
Event fired when a response is received for a server summary request.
Definition: GameClient.cs:97
string LogsBase
Gets the base path for log files.
Definition: GameClient.cs:152
bool IsConnectedToServer
Gets whether or not this client is connected to a server.
Definition: GameClient.cs:192
static void Hide()
Hide the overlay.
bool ToggleFullScreen()
Toggles the full screen state of the game window.
Definition: GameClient.cs:806
void DisableDevice(string deviceId)
Disables a device by ID.
A summary for a game server.
void GoToLaunchScreen(bool upToDate)
Go to the client launch screen.
Definition: GameClient.cs:503
ConnectionToServerFailedHandler ConnectionToServerFailed
Event fired when the game client fails to connect to a server.
Definition: GameClient.cs:77
static bool UpToDate
Whether or not the game is up to date.
Definition: LaunchScreen.cs:17
ServerSpawnedHandler ServerSpawned
Event fired when a requested server spawn is successful.
Definition: GameClient.cs:101
void DisconnectFromServer()
Disconnect from the current server.
Definition: GameClient.cs:690
ConnectedToWorldServerHandler ConnectedToWorldServer
Event fired when the game client successfully connects to the world server.
Definition: GameClient.cs:61
Configuration class for game client.
Definition: ClientConfig.cs:14
int GetPlayerPeerIndex(string playerId)
Get the peer index of the player with the given ID.
Definition: GameClient.cs:454
void FindServers(GameServerType serverType, string mapId, bool isCrucial)
Initiates a server search.
Definition: GameClient.cs:607
Interface for classes which provide information for an action.
string ConfigBase
Gets the base path for configuration files.
Definition: GameClient.cs:144
DisconnectedFromServerHandler DisconnectedFromServer
Event fired when the game client is disconnected from a server.
Definition: GameClient.cs:85
string GetPlayerID(int peerIndex)
Get the ID of the player with the given peer index.
Definition: GameClient.cs:466
string StudyLogsBase
Gets the base path for study logs.
Definition: GameClient.cs:168
void SaveScreenshot()
Saves a timestamped screenshot into the screenshots folder.
Definition: GameClient.cs:820
PlayerJoinedWorldServerHandler OtherPlayerJoinedWorldServer
Event fired when another player joins the world server.
Definition: GameClient.cs:125
void EnableDevice(string deviceId)
Enables a device by ID.
PlayerProfile GetPlayerProfile(int peerIndex)
Get the profile of the player with the given peer index.
Definition: GameClient.cs:490
void ConnectToServer(IPEndPoint serverEndPoint, GameServerType serverType, string mapId, bool isCrucial)
Connect to a server.
Definition: GameClient.cs:663
ClientConfig Config
Gets the configuration for this client.
Definition: GameClient.cs:176
static GameClient Instance
Gets the sole instance of the game client.
Definition: GameClient.cs:136
Manages game devices.
Stores data related to the player profile. Loads from a World Data file and provides runtime operatio...
PlayerLeftServerHandler OtherPlayerLeftServer
Event fired when another player leaves the current server.
Definition: GameClient.cs:121
A class for serializing game data into a stream for propagation between objects and peers...
Definition: GameMessage.cs:14
Main game client class.
Definition: GameClient.cs:16
PlayerJoinedServerHandler OtherPlayerJoinedServer
Event fired when another player joins the current server.
Definition: GameClient.cs:117
static GameObject GetObject(int objectIndex)
Get an object by its object index.
Definition: Sync.Static.cs:143
ConnectionToWorldServerFailedHandler ConnectionToWorldServerFailed
Event fired when the game client fails to connect to the world server.
Definition: GameClient.cs:65
static void RegisterActionInfoProvider(ControlsAction action, IActionInfoProvider actionInfoProvider)
Register an action info provider.
Definition: Controls.cs:90
UJeli MapSettings
Settings for this map, pulled from the world server.
Definition: GameClient.cs:226
A class that manages the DebugLogs. Creates a file for logging Exceptions thrown by Unity as well as ...
Definition: DebugManager.cs:10
string MapID
Gets the ID of the currently loaded map.
Definition: GameClient.cs:213
Unity version of Jeli markup class.
Definition: UJeli.cs:10
static TimelineManager TimelineManager
Gets the Janus timeline manager on this peer.
Definition: Sync.Static.cs:21
PlayerProfile LocalPlayerProfile
Gets the player profile of the local client.
Definition: GameClient.cs:294
This class server two main functions: 1) As a MonoBehaviour, it allows for network synchronization of...
Definition: Sync.cs:13
The spawn-time information of a spawned object.
Definition: SpawnInfo.cs:13
Controls class. Allows for controls queries and controls injection from devices.
Definition: Controls.cs:41
static void ResetHoldTime(ControlsAction action)
Resets the Hold Time of an action. Used to "consume" a held input, such as the 3 second hold for quit...
Definition: Controls.cs:219