123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161 |
- #if ENABLE_MONO && (DEVELOPMENT_BUILD || UNITY_EDITOR)
- #if UNITY_ANDROID && !UNITY_EDITOR
- #define MOBILE_ANDROID
- #endif
- #if UNITY_IOS && !UNITY_EDITOR
- #define MOBILE_IOS
- #endif
- #if MOBILE_ANDROID || MOBILE_IOS
- #define MOBILE
- #endif
- using System;
- using System.Threading.Tasks;
- #if MOBILE_ANDROID
- // not able to use File apis for reading from StreamingAssets
- using UnityEngine.Networking;
- #endif
- using UnityEngine;
- using Debug = UnityEngine.Debug;
- using System.IO;
- namespace SingularityGroup.HotReload {
- // entrypoint for Unity Player builds. Not necessary in Unity Editor.
- internal static class PlayerEntrypoint {
- /// Set when behaviour is created, when you access this instance through the singleton,
- /// you can assume that this field is not null.
- /// <remarks>
- /// In Player code you can assume this is set.<br/>
- /// When in Editor this is usually null.
- /// </remarks>
- static BuildInfo buildInfo { get; set; }
- /// In Player code you can assume this is set (not null)
- public static BuildInfo PlayerBuildInfo => buildInfo;
- #if ENABLE_MONO
- [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterSceneLoad)]
- #endif
- private static void InitOnAppLoad() {
- AppCallbackListener.Init(); // any platform might be using this
- UnityHelper.Init();
- bool onlyPrefabMissing;
- if (!IsPlayerWithHotReload(out onlyPrefabMissing)) {
- if (onlyPrefabMissing) {
- Log.Warning("Hot Reload is not available in this build because one or more build settings were not supported.");
- }
- return;
- }
- TryAutoConnect().Forget();
- }
- static async Task TryAutoConnect() {
- try {
- buildInfo = await GetBuildInfo();
- } catch (Exception e) {
- if (e is IOException) {
- Log.Warning("Hot Reload is not available in this build because one or more build settings were not supported.");
- } else {
- Log.Error($"Uknown exception happened when reading build info\n{e.GetType().Name}: {e.Message}");
- }
- return;
- }
- if (buildInfo == null) {
- Log.Error($"Uknown issue happened when reading build info.");
- return;
- }
- CodePatcher.I.debuggerCompatibilityEnabled = true;
- try {
- var customIp = PlayerPrefs.GetString("HotReloadRuntime.CustomIP", "");
- if (!string.IsNullOrEmpty(customIp)) {
- buildInfo.buildMachineHostName = customIp;
- }
- var customPort = PlayerPrefs.GetString("HotReloadRuntime.CustomPort", "");
- if (!string.IsNullOrEmpty(customPort)) {
- buildInfo.buildMachinePort = int.Parse(customPort);
- }
- if (buildInfo.BuildMachineServer == null) {
- Prompts.ShowRetryDialog(null);
- } else {
- // try reach server running on the build machine.
- TryConnect(buildInfo.BuildMachineServer, auto: true).Forget();
- }
- } catch (Exception ex) {
- Log.Exception(ex);
- }
- }
- public static Task TryConnectToIpAndPort(string ip, int port) {
- ip = ip.Trim();
- if (buildInfo == null) {
- throw new ArgumentException("Build info not found");
- }
- buildInfo.buildMachineHostName = ip;
- buildInfo.buildMachinePort = port;
- PlayerPrefs.SetString("HotReloadRuntime.CustomIP", ip);
- PlayerPrefs.SetString("HotReloadRuntime.CustomPort", port.ToString());
- return TryConnect(buildInfo.BuildMachineServer, auto: false);
- }
- public static async Task TryConnect(PatchServerInfo serverInfo, bool auto) {
- // try reach server running on the build machine.
- var handshake = PlayerCodePatcher.UpdateHost(serverInfo);
- await Task.WhenAny(handshake, Task.Delay(TimeSpan.FromSeconds(40)));
- await ThreadUtility.SwitchToMainThread();
- var handshakeResults = await handshake;
- var handshakeOk = handshakeResults.HasFlag(ServerHandshake.Result.Verified);
- if (!handshakeOk) {
- Log.Debug("ShowRetryPrompt because handshake result is {0}", handshakeResults);
- Prompts.ShowRetryDialog(serverInfo, handshakeResults, auto);
- // cancel trying to connect. They can use the retry button
- PlayerCodePatcher.UpdateHost(null).Forget();
- }
- Log.Info($"Server is healthy after first handshake? {handshakeOk}");
- }
- /// on Android, streaming assets are inside apk zip, which can only be read using unity web request
- private static async Task<BuildInfo> GetBuildInfo() {
- var path = BuildInfo.GetStoredPath();
- #if MOBILE_ANDROID
- var json = await RequestHelper.GetAsync(path);
- return await Task.Run(() => BuildInfo.FromJson(json));
- #else
- return await Task.Run(() => {
- return BuildInfo.FromJson(File.ReadAllText(path));
- });
- #endif
- }
- public static bool IsPlayer() => !Application.isEditor;
- public static bool IsPlayerWithHotReload() {
- bool _;
- return IsPlayerWithHotReload(out _);
- }
- public static bool IsPlayerWithHotReload(out bool onlyPrefabMissing) {
- onlyPrefabMissing = false;
- if (!IsPlayer() || !RuntimeSupportsHotReload || !HotReloadSettingsObject.I.IncludeInBuild) {
- return false;
- }
- onlyPrefabMissing = !HotReloadSettingsObject.I.PromptsPrefab;
- return !onlyPrefabMissing;
- }
-
- public static bool RuntimeSupportsHotReload {
- get {
- #if DEVELOPMENT_BUILD && ENABLE_MONO
- return true;
- #else
- return false;
- #endif
- }
- }
- }
- }
- #endif
|