void OnEnable() { encryptionKeysEnabled = UMAABMSettings.GetEncryptionEnabled(); currentEncryptionPassword = newEncryptionPassword = UMAABMSettings.GetEncryptionPassword(); currentEncryptionSuffix = newEncryptionSuffix = UMAABMSettings.GetEncryptionSuffix(); if (currentEncryptionSuffix == "") { currentEncryptionSuffix = newEncryptionSuffix = DEFAULT_ENCRYPTION_SUFFIX; } currentEncodeNamesSetting = newEncodeNamesSetting = UMAABMSettings.GetEncodeNames(); #if ENABLE_IOS_APP_SLICING currentAppSlicingSetting = UMAABMSettings.GetBuildForSlicing(); #endif _enableBundleIndexVersioning = UMAABMSettings.EnableBundleIndexVersioning; //localAssetBundleServer status _enableLocalAssetBundleServer = EditorPrefs.GetBool(Application.dataPath + "LocalAssetBundleServerEnabled"); _port = EditorPrefs.GetInt(Application.dataPath + "LocalAssetBundleServerPort", 7888); //When the window is opened we still need to tell the user if the port is available so if (!_enableLocalAssetBundleServer) { UpdateServer(true); ServerStop(); if (serverException) { portError = true; } } else { UpdateServer(); } }
public static byte[] Encrypt(byte[] value, ref byte[] IVout) { var pass = UMAABMSettings.GetEncryptionPassword(); if (String.IsNullOrEmpty(pass)) { throw new Exception("[EncryptUtil] could not perform any encryption because not encryption password was set in UMAAssetBundleManager."); } IVout = GenerateIV(pass); return(Encrypt(BuildKey(pass, IVout), value)); }
void OnFocus() { encryptionKeysEnabled = UMAABMSettings.GetEncryptionEnabled(); currentEncryptionPassword = newEncryptionPassword = UMAABMSettings.GetEncryptionPassword(); currentEncryptionSuffix = newEncryptionSuffix = UMAABMSettings.GetEncryptionSuffix(); if (currentEncryptionSuffix == "") { currentEncryptionSuffix = newEncryptionSuffix = DEFAULT_ENCRYPTION_SUFFIX; } currentEncodeNamesSetting = newEncodeNamesSetting = UMAABMSettings.GetEncodeNames(); #if ENABLE_IOS_APP_SLICING currentAppSlicingSetting = UMAABMSettings.GetBuildForSlicing(); #endif }
public static void BuildAssetBundles() { var thisIndexAssetPath = ""; var thisEncryptionAssetPath = ""; try { // Choose the output path according to the build target. string outputPath = CreateAssetBundleDirectory(); var options = BuildAssetBundleOptions.None; bool shouldCheckODR = EditorUserBuildSettings.activeBuildTarget == BuildTarget.iOS; #if UNITY_TVOS shouldCheckODR |= EditorUserBuildSettings.activeBuildTarget == BuildTarget.tvOS; #endif if (shouldCheckODR) { #if ENABLE_IOS_ON_DEMAND_RESOURCES if (PlayerSettings.iOS.useOnDemandResources) { options |= BuildAssetBundleOptions.UncompressedAssetBundle; } else if (UMAABMSettings.GetEncryptionEnabled()) { options |= BuildAssetBundleOptions.ChunkBasedCompression; } #endif #if ENABLE_IOS_APP_SLICING if (UMAABMSettings.GetBuildForSlicing()) { options |= BuildAssetBundleOptions.UncompressedAssetBundle; } else if (!PlayerSettings.iOS.useOnDemandResources && UMAABMSettings.GetEncryptionEnabled()) { options |= BuildAssetBundleOptions.ChunkBasedCompression; } #endif } if (UMAABMSettings.GetEncryptionEnabled()) { if (!shouldCheckODR) { options |= BuildAssetBundleOptions.ChunkBasedCompression; } options |= BuildAssetBundleOptions.ForceRebuildAssetBundle; } //AssetBundleIndex AssetBundleIndex thisIndex = ScriptableObject.CreateInstance <AssetBundleIndex>(); string[] assetBundleNamesArray = AssetDatabase.GetAllAssetBundleNames(); //Generate a buildmap as we go AssetBundleBuild[] buildMap = new AssetBundleBuild[assetBundleNamesArray.Length + 1]; //+1 for the index bundle for (int i = 0; i < assetBundleNamesArray.Length; i++) { string bundleName = assetBundleNamesArray[i]; string[] assetBundleAssetsArray = AssetDatabase.GetAssetPathsFromAssetBundle(bundleName); //If there are no assets added to this bundle show a warning telling the user to remove Unused asset bundle names if (assetBundleAssetsArray == null || assetBundleAssetsArray.Length == 0) { Debug.Log(assetBundleNamesArray[i] + " was an empty assetBundle. Please do 'Remove Unused Names' in the 'Asset Labels' section of the Inspector"); } thisIndex.bundlesIndex.Add(new AssetBundleIndex.AssetBundleIndexList(bundleName)); if (bundleName.IndexOf('.') > -1) { buildMap[i].assetBundleName = bundleName.Split('.')[0]; buildMap[i].assetBundleVariant = bundleName.Split('.')[1]; } else { buildMap[i].assetBundleName = bundleName; } buildMap[i].assetNames = assetBundleAssetsArray; foreach (string path in assetBundleAssetsArray) { var sysPath = Path.Combine(Application.dataPath, path); var filename = Path.GetFileNameWithoutExtension(sysPath); var tempObj = AssetDatabase.LoadMainAssetAtPath(path); thisIndex.bundlesIndex[i].AddItem(filename, tempObj); } } thisIndexAssetPath = "Assets/" + Utility.GetPlatformName() + "Index.asset"; thisIndex.name = "AssetBundleIndex"; AssetDatabase.CreateAsset(thisIndex, thisIndexAssetPath); AssetImporter thisIndexAsset = AssetImporter.GetAtPath(thisIndexAssetPath); thisIndexAsset.assetBundleName = Utility.GetPlatformName() + "index"; buildMap[assetBundleNamesArray.Length].assetBundleName = Utility.GetPlatformName() + "index"; buildMap[assetBundleNamesArray.Length].assetNames = new string[1] { "Assets/" + Utility.GetPlatformName() + "Index.asset" }; //Build the current state so we can get the AssetBundleManifest object and add its values to OUR index var assetBundleManifest = BuildPipeline.BuildAssetBundles(outputPath, buildMap, options, EditorUserBuildSettings.activeBuildTarget); if (assetBundleManifest == null) { throw new System.Exception("Your assetBundles did not build properly."); } //reload the saved index (TODO may not be necessary) thisIndex = AssetDatabase.LoadAssetAtPath <AssetBundleIndex>("Assets/" + Utility.GetPlatformName() + "Index.asset"); //Get any bundles with variants string[] bundlesWithVariant = assetBundleManifest.GetAllAssetBundlesWithVariant(); thisIndex.bundlesWithVariant = bundlesWithVariant; //then loop over each bundle in the bundle names and get the bundle specific data for (int i = 0; i < assetBundleNamesArray.Length; i++) { string[] assetBundleAssetsArray = AssetDatabase.GetAssetPathsFromAssetBundle(assetBundleNamesArray[i]); //If there are no assets added to this bundle continue because it wont be in the resulting assetBundleManifest if (assetBundleAssetsArray == null) { continue; } string assetBundleHash = assetBundleManifest.GetAssetBundleHash(assetBundleNamesArray[i]).ToString(); string[] allDependencies = assetBundleManifest.GetAllDependencies(assetBundleNamesArray[i]); string[] directDependencies = assetBundleManifest.GetDirectDependencies(assetBundleNamesArray[i]); thisIndex.bundlesIndex[i].assetBundleHash = assetBundleHash; thisIndex.bundlesIndex[i].allDependencies = allDependencies; thisIndex.bundlesIndex[i].directDependencies = directDependencies; //Add suffixed names to the index if enabled and we are using encrption //we cant append the suffix to the index file because when we are loading we dont know the set suffix or suffixed names until we have the index //it also cant be the same as the unencrypted name because it needs a different memory address, so its going to have to be name + "encrypted" if (UMAABMSettings.GetEncryptionEnabled()) { var encryptedBundleName = assetBundleNamesArray[i] == Utility.GetPlatformName() + "index" ? assetBundleNamesArray[i] + "encrypted" : assetBundleNamesArray[i] + UMAABMSettings.GetEncryptionSuffix(); if (UMAABMSettings.GetEncodeNames() && assetBundleNamesArray[i] != Utility.GetPlatformName() + "index") { encryptedBundleName = EncryptionUtil.EncodeFileName(encryptedBundleName); } thisIndex.bundlesIndex[i].encryptedName = encryptedBundleName; } } var relativeAssetBundlesOutputPathForPlatform = Path.Combine(Utility.AssetBundlesOutputPath, Utility.GetPlatformName()); //Update and Save the index asset and build again. This will store the updated asset in the windowsindex asset bundle EditorUtility.SetDirty(thisIndex); AssetDatabase.SaveAssets(); //Build the Index AssetBundle var indexBuildMap = new AssetBundleBuild[1]; indexBuildMap[0] = buildMap[assetBundleNamesArray.Length]; BuildPipeline.BuildAssetBundles(outputPath, indexBuildMap, options, EditorUserBuildSettings.activeBuildTarget); //Save a json version of the data- this can be used for uploading to a server to update a database or something string thisIndexJson = JsonUtility.ToJson(thisIndex); var thisIndexJsonPath = Path.Combine(relativeAssetBundlesOutputPathForPlatform, Utility.GetPlatformName().ToLower()) + "index.json"; File.WriteAllText(thisIndexJsonPath, thisIndexJson); //Build Encrypted Bundles if (UMAABMSettings.GetEncryptionEnabled()) { var encryptedBuildMap = new AssetBundleBuild[1]; var EncryptionAsset = ScriptableObject.CreateInstance <UMAEncryptedBundle>(); EncryptionAsset.name = "EncryptedData"; thisEncryptionAssetPath = "Assets/EncryptedData.asset"; AssetDatabase.CreateAsset(EncryptionAsset, thisEncryptionAssetPath); //var encryptedOutputPath = Path.Combine(outputPath, "Encrypted"); var encryptedOutputPath = Path.Combine(Utility.AssetBundlesOutputPath, Path.Combine("Encrypted", Utility.GetPlatformName())); if (!Directory.Exists(encryptedOutputPath)) { Directory.CreateDirectory(encryptedOutputPath); } for (int bmi = 0; bmi < buildMap.Length; bmi++) //-1 to not include the index bundle (or maybe we do encrypt the index bundle?) { var thisEncryptionAsset = AssetDatabase.LoadAssetAtPath <UMAEncryptedBundle>(thisEncryptionAssetPath); //get the data from the unencrypted bundle and encrypt it into the EncryptedData asset thisEncryptionAsset.GenerateData(buildMap[bmi].assetBundleName, Path.Combine(relativeAssetBundlesOutputPathForPlatform, buildMap[bmi].assetBundleName)); EditorUtility.SetDirty(thisEncryptionAsset); AssetDatabase.SaveAssets(); //Sort out the name of this encrypted bundle var encryptedBundleName = ""; if (buildMap[bmi].assetBundleName != Utility.GetPlatformName() + "index") { encryptedBundleName = buildMap[bmi].assetBundleName + UMAABMSettings.GetEncryptionSuffix(); if (UMAABMSettings.GetEncodeNames() && buildMap[bmi].assetBundleName != Utility.GetPlatformName() + "index") { encryptedBundleName = EncryptionUtil.EncodeFileName(encryptedBundleName); } } else { encryptedBundleName = buildMap[bmi].assetBundleName + "encrypted"; } //set the Build map value encryptedBuildMap[0].assetBundleName = encryptedBundleName; encryptedBuildMap[0].assetNames = new string[1] { "Assets/EncryptedData.asset" }; //and build the bundle BuildPipeline.BuildAssetBundles(encryptedOutputPath, encryptedBuildMap, BuildAssetBundleOptions.None, EditorUserBuildSettings.activeBuildTarget); } //save a json index in there too var thisIndexJsonEncPath = Path.Combine(encryptedOutputPath, Utility.GetPlatformName().ToLower()) + "indexencrypted.json"; File.WriteAllText(thisIndexJsonEncPath, thisIndexJson); AssetDatabase.DeleteAsset(thisEncryptionAssetPath); } //Now we can remove the temp Index item from the assetDatabase AssetDatabase.DeleteAsset(thisIndexAssetPath); //And remove its assetBundle name from the assetBundleNames AssetDatabase.RemoveAssetBundleName(Utility.GetPlatformName().ToLower() + "index", false); Debug.Log("Asset Bundles built successfully for platform " + Utility.GetPlatformName() + (UMAABMSettings.GetEncryptionEnabled() ? " (Encrypted)!" : "!")); } catch (System.Exception e) { if (thisIndexAssetPath != "") { AssetDatabase.DeleteAsset(thisIndexAssetPath); } if (thisEncryptionAssetPath != "") { AssetDatabase.DeleteAsset(thisEncryptionAssetPath); } //And remove its assetBundle name from the assetBundleNames AssetDatabase.RemoveAssetBundleName(Utility.GetPlatformName().ToLower() + "index", false); Debug.LogError("Your AssetBundles did not build properly. Error Message: " + e.Message + " Error Exception: " + e.InnerException + " Error StackTrace: " + e.StackTrace); } }
void OnGUI() { scrollPos = EditorGUILayout.BeginScrollView(scrollPos, false, true); EditorGUILayout.BeginVertical(GUILayout.Width(EditorGUIUtility.currentViewWidth - 20f)); EditorGUILayout.Space(); GUILayout.Label("UMA AssetBundle Manager", EditorStyles.boldLabel); BeginVerticalPadded(5, new Color(0.75f, 0.875f, 1f)); GUILayout.Label("AssetBundle Options", EditorStyles.boldLabel); //AssetBundle Build versioning EditorGUI.BeginChangeCheck(); _enableBundleIndexVersioning = EditorGUILayout.ToggleLeft("Enable AssetBundle Index Versioning", _enableBundleIndexVersioning); if (EditorGUI.EndChangeCheck()) { UMAABMSettings.EnableBundleIndexVersioning = _enableBundleIndexVersioning; } if (_enableBundleIndexVersioning) { BeginVerticalIndented(10, new Color(0.75f, 0.875f, 1f)); EditorGUILayout.HelpBox("Sets the 'bundlesPlayerVersion' value of the AssetBundleIndex when you build your bundles. You can use this to determine if your app needs to force the user to go online to update their bundles and/or application (its up to you how you do that though!). ", MessageType.Info); EditorGUI.BeginChangeCheck(); _bundleIndexVersioningMethod = (UMAABMSettingsStore.BundleIndexVersioningOpts)EditorGUILayout.EnumPopup("Bundles Versioning Method", _bundleIndexVersioningMethod); if (EditorGUI.EndChangeCheck()) { UMAABMSettings.BundleIndexVersioningMethod = _bundleIndexVersioningMethod; } if (_bundleIndexVersioningMethod == UMAABMSettingsStore.BundleIndexVersioningOpts.Custom) { EditorGUI.BeginChangeCheck(); _bundleIndexCustomValue = EditorGUILayout.TextField("Bundles Index Player Version", _bundleIndexCustomValue); if (EditorGUI.EndChangeCheck()) { UMAABMSettings.BundleIndexCustomValue = _bundleIndexCustomValue; } } else { var currentBuildVersion = Application.version; if (string.IsNullOrEmpty(currentBuildVersion)) { EditorGUILayout.HelpBox("Please be sure to set a 'Version' number (eg 1.0, 2.1.0) in Edit->ProjectSettings->Player->Version", MessageType.Warning); } else { EditorGUILayout.HelpBox("Current 'Version' number (" + currentBuildVersion + ") will be used. You can change this in Edit->ProjectSettings->Player->Version.", MessageType.Info); } } EditorGUILayout.Space(); EndVerticalIndented(); } //Asset Bundle Encryption //defined here so we can modify the message if encryption settings change string buildBundlesMsg = ""; MessageType buildBundlesMsgType = MessageType.Info; EditorGUI.BeginChangeCheck(); encryptionKeysEnabled = EditorGUILayout.ToggleLeft("Enable AssetBundle Encryption", encryptionKeysEnabled); if (EditorGUI.EndChangeCheck()) { //If encryption was turned ON generate the encryption password if necessary if (encryptionKeysEnabled) { if (currentEncryptionPassword == "") { if (UMAABMSettings.GetEncryptionPassword() != "") { currentEncryptionPassword = UMAABMSettings.GetEncryptionPassword(); } else { currentEncryptionPassword = EncryptionUtil.GenerateRandomPW(); } } UMAABMSettings.SetEncryptionPassword(currentEncryptionPassword); buildBundlesMsg = "You have turned on encryption and need to Rebuild your bundles to encrypt them."; buildBundlesMsgType = MessageType.Warning; } else { UMAABMSettings.DisableEncryption(); currentEncryptionPassword = ""; } } if (encryptionKeysEnabled) { BeginVerticalIndented(10, new Color(0.75f, 0.875f, 1f)); //tip EditorGUILayout.HelpBox("Make sure you turn on 'Use Encrypted Bundles' in the 'DynamicAssetLoader' components in your scenes.", MessageType.Info); //Encryption key //If we can work out a way for people to download a key we can use this tip and the 'EncryptionKeyURL' field //string encryptionKeyToolTip = "This key is used to generate the required encryption keys used when encrypting your bundles. If you change this key you will need to rebuild your bundles otherwise they wont decrypt. If you use the 'Encryption Key URL' field below you MUST ensure this field is set to the same key the url will return."; string encryptionKeyToolTip = "This key is used to generate the required encryption keys used when encrypting your bundles. If you change this key you will need to rebuild your bundles otherwise they wont decrypt."; EditorGUILayout.LabelField(new GUIContent("Bundle Encryption Password", encryptionKeyToolTip)); EditorGUILayout.BeginHorizontal(); if (!manualEditEncryptionKey) { if (GUILayout.Button(new GUIContent("Edit", encryptionKeyToolTip))) { manualEditEncryptionKey = true; } EditorGUI.BeginDisabledGroup(!manualEditEncryptionKey); EditorGUILayout.TextField("", UMAABMSettings.GetEncryptionPassword()); //THis bloody field WILL NOT update when you click edit, then canel, the value stays EditorGUI.EndDisabledGroup(); } else { EditorGUI.BeginChangeCheck(); newEncryptionPassword = EditorGUILayout.TextArea(newEncryptionPassword); if (EditorGUI.EndChangeCheck()) { encryptionSaveButEnabled = EncryptionUtil.PasswordValid(newEncryptionPassword); } if (encryptionSaveButEnabled) { if (GUILayout.Button(new GUIContent("Save"), GUILayout.MaxWidth(60))) { currentEncryptionPassword = newEncryptionPassword; UMAABMSettings.SetEncryptionPassword(newEncryptionPassword); EditorGUIUtility.keyboardControl = 0; manualEditEncryptionKey = false; } } else { GUI.enabled = false; if (GUILayout.Button(new GUIContent("Save", "Your Encryptiom Password should be at least 16 characters long"), GUILayout.MaxWidth(60))) { //Do nothing } GUI.enabled = true; } if (GUILayout.Button(new GUIContent("Cancel", "Reset to previous value: " + currentEncryptionPassword), GUILayout.MaxWidth(60))) { manualEditEncryptionKey = false; newEncryptionPassword = currentEncryptionPassword = UMAABMSettings.GetEncryptionPassword(); encryptionSaveButEnabled = false; EditorGUIUtility.keyboardControl = 0; } } EditorGUILayout.EndHorizontal(); //EncryptionKey URL //not sure how this would work- the delivered key would itself need to be encrypted probably //Encrypted bundle suffix string encryptionSuffixToolTip = "This suffix is appled to the end of your encrypted bundle names when they are built. Must be lower case and alphaNumeric. Cannot be empty. Defaults to " + DEFAULT_ENCRYPTION_SUFFIX; EditorGUILayout.LabelField(new GUIContent("Encrypted Bundle Suffix", encryptionSuffixToolTip)); EditorGUILayout.BeginHorizontal(); if (!manualEditEncryptionSuffix) { if (GUILayout.Button(new GUIContent("Edit", encryptionSuffixToolTip))) { manualEditEncryptionSuffix = true; } EditorGUI.BeginDisabledGroup(!manualEditEncryptionSuffix); EditorGUILayout.TextField(new GUIContent("", encryptionSuffixToolTip), currentEncryptionSuffix); EditorGUI.EndDisabledGroup(); } else { newEncryptionSuffix = EditorGUILayout.TextArea(newEncryptionSuffix); if (GUILayout.Button(new GUIContent("Save"))) { if (newEncryptionSuffix != "") { Regex rgx = new Regex("[^a-zA-Z0-9 -]"); var suffixToSend = rgx.Replace(newEncryptionSuffix, ""); currentEncryptionSuffix = suffixToSend; UMAABMSettings.SetEncryptionSuffix(suffixToSend.ToLower()); EditorGUIUtility.keyboardControl = 0; manualEditEncryptionSuffix = false; } } } EditorGUILayout.EndHorizontal(); //Encode Bundle Names string encodeBundleNamesTooltip = "If true encrypted bundle names will be base64 encoded"; EditorGUI.BeginChangeCheck(); newEncodeNamesSetting = EditorGUILayout.ToggleLeft(new GUIContent("Encode Bundle Names", encodeBundleNamesTooltip), currentEncodeNamesSetting); if (EditorGUI.EndChangeCheck()) { currentEncodeNamesSetting = newEncodeNamesSetting; UMAABMSettings.SetEncodeNames(newEncodeNamesSetting); } EndVerticalIndented(); } #if ENABLE_IOS_APP_SLICING string AppSlicingTooltip = "If true will build bundles uncompressed for use with iOS Resources Catalogs"; EditorGUI.BeginChangeCheck(); bool newAppSlicingSetting = EditorGUILayout.ToggleLeft(new GUIContent("Build for iOS App Slicing", AppSlicingTooltip), currentAppSlicingSetting); if (EditorGUI.EndChangeCheck()) { currentAppSlicingSetting = newAppSlicingSetting; UMAABMSettings.SetBuildForSlicing(newAppSlicingSetting); } #endif //Asset Bundle Building EditorGUILayout.Space(); string buttonBuildAssetBundlesText = "Build AssetBundles"; //Now defined above the encryption //string buildBundlesText = "Click the button below to build your bundles if you have not done so already."; string fullPathToBundles = Path.Combine(Directory.GetParent(Application.dataPath).FullName, Utility.AssetBundlesOutputPath); string fullPathToPlatformBundles = Path.Combine(fullPathToBundles, Utility.GetPlatformName()); //if we have not built any asset bundles there wont be anything in the cache to clear bool showClearCache = false; if (Directory.Exists(fullPathToPlatformBundles)) { buttonBuildAssetBundlesText = "Rebuild AssetBundles"; buildBundlesMsg = buildBundlesMsg == "" ? "Rebuild your assetBundles to reflect your latest changes" : buildBundlesMsg; showClearCache = true; } else { buildBundlesMsg = "You have not built your asset bundles for " + EditorUserBuildSettings.activeBuildTarget.ToString() + " yet. Click this button to build them."; buildBundlesMsgType = MessageType.Warning; showClearCache = false; } EditorGUILayout.HelpBox(buildBundlesMsg, buildBundlesMsgType); if (GUILayout.Button(buttonBuildAssetBundlesText)) { BuildScript.BuildAssetBundles(); #if UNITY_2017_1_OR_NEWER Caching.ClearCache(); #else Caching.CleanCache(); #endif return; } EndVerticalPadded(5); EditorGUILayout.Space(); //Local AssetBundleServer BeginVerticalPadded(5f, new Color(0.75f, 0.875f, 1f)); GUILayout.Label("AssetBundle Testing Server", EditorStyles.boldLabel); EditorGUILayout.HelpBox("Once you have built your bundles this local Testing Server can be enabled and it will load those AssetBundles rather than the files inside the project.", MessageType.Info); if (!BuildScript.CanRunLocally(EditorUserBuildSettings.activeBuildTarget)) { EditorGUILayout.HelpBox("Builds for " + EditorUserBuildSettings.activeBuildTarget.ToString() + " cannot access this local server, but you can still use it in the editor.", MessageType.Warning); } bool updateURL = false; EnableLocalAssetBundleServer = EditorGUILayout.Toggle("Start Server", EnableLocalAssetBundleServer); //If the server is off we need to show the user a message telling them that they will have to have uploaded their bundles to an external server //and that they need to set the address of that server in DynamicAssetLoader int newPort = Port; EditorGUI.BeginChangeCheck(); newPort = EditorGUILayout.IntField("Port", Port); if (EditorGUI.EndChangeCheck()) { if (newPort != Port) { if (_activeHost != null && _activeHost != "") { ActiveHost = _activeHost.Replace(":" + Port.ToString(), ":" + newPort.ToString()); } Port = newPort; UpdateHosts(); //we need to start the server to see if it works with this port- regardless of whether it is turned on or not. if (!EnableLocalAssetBundleServer) { UpdateServer(true); } else { UpdateServer(); } if (serverException == false) { //We can use the set IP with this port so update it if (EnableLocalAssetBundleServer) { SimpleWebServer.ServerURL = ActiveHost; } } else { //We CANT use the set IP with this port so set the saved URL to "" and tell the user the Port is in use elsewhere SimpleWebServer.ServerURL = ""; EnableLocalAssetBundleServer = false; portError = true; } } } if (!EnableLocalAssetBundleServer) { if (portError) { EditorGUILayout.HelpBox("There are no hosts available for that port. Its probably in use by another application. Try another.", MessageType.Warning); } else { EditorGUILayout.HelpBox("When the local server is not running the game will play in Simulation Mode OR if you have set the 'RemoteServerURL' for each DynamicAssetLoader, bundles will be downloaded from that location.", MessageType.Warning); if (EditorUserBuildSettings.activeBuildTarget == BuildTarget.WebGL) { EditorGUILayout.HelpBox("WARNING: AssetBundles in WebGL builds that you run locally WILL NOT WORK unless the local server is turned on, and you build using the button below!", MessageType.Warning); } } } EditorGUILayout.Space(); if (_hosts != null && _hosts.Length > 0 && EnableLocalAssetBundleServer) { if (_activeHost == null || _activeHost == "") { ActiveHost = _hosts[0]; } int activeHostInt = 0; string[] hostsStrings = new string[_hosts.Length]; for (int i = 0; i < _hosts.Length; i++) { hostsStrings[i] = _hosts[i].Replace("http://", "").TrimEnd(new char[] { '/' }); if (_hosts[i] == _activeHost) { activeHostInt = i; } } EditorGUI.BeginChangeCheck(); int newActiveHostInt = EditorGUILayout.Popup("Host Address: http://", activeHostInt, hostsStrings); if (EditorGUI.EndChangeCheck()) { if (newActiveHostInt != activeHostInt) { ActiveHost = _hosts[newActiveHostInt]; updateURL = true; } } } EditorGUILayout.Space(); if (showClearCache) //no point in showing a button for bundles that dont exist - or is there? The user might be using a remote url to download assetbundles without the localserver? { EditorGUILayout.HelpBox("You can clear the cache to force asset bundles to be redownloaded.", MessageType.Info); if (GUILayout.Button("Clean the Cache")) { #if UNITY_2017_1_OR_NEWER _statusMessage = Caching.ClearCache() ? "Cache Cleared." : "Error clearing cache."; #else _statusMessage = Caching.CleanCache() ? "Cache Cleared." : "Error clearing cache."; #endif } EditorGUILayout.Space(); } EditorGUILayout.Space(); GUILayout.Label("Server Status"); if (_statusMessage != null) { EditorGUILayout.HelpBox(_statusMessage, MessageType.None); } if (SimpleWebServer.Instance != null) { //GUILayout.Label("Server Request Log"); serverRequestLogOpen = EditorGUILayout.Foldout(serverRequestLogOpen, "Server Request Log"); if (serverRequestLogOpen) { EditorGUILayout.HelpBox(SimpleWebServer.Instance.GetLog(), MessageType.Info); } } if (updateURL) { SimpleWebServer.ServerURL = ActiveHost; } EndVerticalPadded(5); EditorGUILayout.Space(); //Testing Build- only show this if we can run a build for the current platform (i.e. if its not iOS or Android) if (BuildScript.CanRunLocally(EditorUserBuildSettings.activeBuildTarget)) { BeginVerticalPadded(5, new Color(0.75f, 0.875f, 1f)); GUILayout.Label("Local Testing Build", EditorStyles.boldLabel); //if the bundles are built and the server is turned on then the user can use this option otherwise there is no point //But we will show them that this option is available even if this is not the case if (!showClearCache || !EnableLocalAssetBundleServer) { EditorGUI.BeginDisabledGroup(true); } EditorGUILayout.HelpBox("Make a testing Build that uses the Local Server using the button below.", MessageType.Info); developmentBuild = EditorGUILayout.Toggle("Development Build", developmentBuild); if (GUILayout.Button("Build and Run!")) { BuildScript.BuildAndRunPlayer(developmentBuild); } if (!showClearCache || !EnableLocalAssetBundleServer) // { EditorGUI.EndDisabledGroup(); } EditorGUILayout.Space(); EndVerticalPadded(5); EditorGUILayout.Space(); } //END SCROLL VIEW //for some reason when we build or build assetbundles when this window is open we get an error //InvalidOperationException: Operation is not valid due to the current state of the object //so try catch is here as a nasty hack to get rid of it try { EditorGUILayout.EndVertical(); EditorGUILayout.EndScrollView(); } catch { } }