Unity asset bundle server automation - c#

I am developing an application in Unity where users can upload their own 3d-models. I have been searching for ways to implement this and the best way to load models from all types seems to be asset bundles. To create these bundles on a server i want to run Unity in batch mode and create the bundles from a static method.
The problem I'm facing is that it seems to be impossible to include objects in a asset bundle from script. In the editor you just select the asset bundle name but to automate this, that won't be possible.

Found the answer using the AssetImporter as i intended in the first place. For some reason I tought I had to instantiate the object in order to bundle it. That was a false assumption and by just adding the project path you can assign a bundlename to a asset.
foreach (string file in filesInFolder)
{
if (!file.Contains(".meta"))
{
AssetImporter importer = AssetImporter.GetAtPath("Assets/models/" + file);
if (importer != null)
{
importer.assetBundleName = BundleName;
Debug.Log("assetBundlesAssigned");
}
else
{
Debug.Log("No asset selected");
complete = false;
}
}
}
When all the assets are assigned you can build them as usual like so.
public static void ExecBuildAssetBundles()
{
Debug.Log("Building bundle");
BuildPipeline.BuildAssetBundles("Assets/AssetBundles", BuildAssetBundleOptions.None, BuildTarget.Android);
}

Related

PlayerPrefs working on unity editor but not in build

I've looking for info to try to solve my problem and I just can't figure out what it's causing it. Player Prefs seem to work fine in unity editor, but once i make a build for Android or PC they are all gone. I have PlayerPrefs.deleteAll no where in my project.
I have 3 scenes: Menu, Game and GameOver. When I start the Menu scene, I run this script attached to the MainCamera:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class prefs : MonoBehaviour
{
public static int bestRecord;
// Start is called before the first frame update
void Start()
{
bestRecord = PlayerPrefs.GetInt("K", 1);
Debug.Log(PlayerPrefs.GetInt("K").ToString());
}
}
When I go into the Game scene, my score is a TextMeshProUGUI that is constantly update by an InvokeRepeating:
public TextMeshProUGUI points;
void Start()
{
stop = false;
InvokeRepeating("subirMetros", 0f, 0.01f);
}
private void subirMetros()
{
if (stop == false)
{
points.SetText(Math.Round(character.transform.position.x, 0) + "");
}
}
//GameOver is called when the player dies
public void GameOver()
{
stop = true;
CancelInvoke("subirMetros");
int finalPoints = Int32.Parse(points.text);
int recordActual = PlayerPrefs.GetInt("K");
if (recordActual < finalPoints)
{
PlayerPrefs.SetInt("K", finalPoints);
}
SceneManager.LoadScene("GameOver");
}
}
Finally, when starting the GameOver scene, I get once again the PlayerPrefs that are supposedly saved before I get to the scene:
public TextMeshProUGUI record;
void Start()
{
record.text = PlayerPrefs.GetInt("K").ToString();
}
The weird thing is that this is working in the unity editor, but not when i build it. I would be very grateful if someone could help me, thanks.
I know this is an old post (forgive me for necro) but it came up as a google search result, and i ran into the same issue.
I had the same issue with playerprefs, i was saving an encrypted file where i used a playerprefs together with a generated key for a hash value. When i saved the game in the editor and ran in the build i couldnt load my save file. This was for windows though. After some debugging and digging I found out that unity saves playerprefs two different places for both editor and application builds:
according to this article
https://virtual-reality-piano.medium.com/solved-where-is-unitys-playerprefs-stored-on-windows-d61d504585e9
Your unity editor saves it at the path: ‘HKEY_CURRENT_USER\SOFTWARE\Unity\UnityEditor\CompanyName\ProjectName’
But, when you build your application, the player prefs are saved at:
'HKEY_CURRENT_USER\SOFTWARE\CompanyName\ProjectName' (where Company name is the name of your company, and project name is the name of your project).
I had to go in and delete the registry files in both places, because say i was saving a Save File with the name DefaultPlayer, then the editor would associate that save with the registry file from the editor. But when i build to an application, the save file would still persist in Application.PersistentPath, but it's registry file would not exist, because it wasn't created yet in the application's registry file.
Sorry for the confusing post and necro, but this is what fixed save file problems for me from editor to application builds. (note this is on windows so dont know if it applies to android as well). Hope it helps anyone else running into the same problem
note you would have to delete both files everytime you test in editor and on builds, or as someone suggested in a comment above, use the #if UNITY_EDITOR pragma to avoid the error
I read your post and I have a similar problem with this.
Before I have built an apk file but it was not working on the emulator.
But it was working on Unity Editor well.
I couldn't find the reason for this problem but I think there is a problem when the scene is loading using SceneManager.LoadScene().
When I don't use this function, the error was fixed.
If you fix this problem, please post how did you do.
And I think it is better to avoid errors than fixing errors.
Good luck.

DLL: Library of Images [duplicate]

I cannot get Unity Assetbundles working in an iOS build.
In Unity I build the assetbundles:
using UnityEditor;
public class CreateAssetBundles
{
[MenuItem("Assets/Build AssetBundles")]
static void BuildAllAssetBundles()
{
BuildPipeline.BuildAssetBundles("Assets/AssetBundles", BuildAssetBundleOptions.None, BuildTarget.iOS);
}
}
And they work fine in Unity. using them with
AssetBundle bundleLoadRequest = AssetBundle.LoadFromFile("file://" + Application.dataPath + "/AssetBundles/iOS/" + myassetbundlename.ToString());
and/or
WWW wwww = WWW.LoadFromCacheOrDownload("file://" + Application.dataPath + "/AssetBundles/iOS/" + myassetbundlename.ToString(), 4);
(Without the "file://" prefix, the bundles won't work in Unity nor Xcode)
I build the project to Xcode and run it in Xcode and receive this error:
Unable to open archive file:
/Users/user/Documents/Workspaces/unityproject/Assets/AssetBundles/iOS/lchairanimations
It might be related somehow to setting the correct path, but as I have copied the assetbundle folder afterwards to Xcode project, the problem persists.
In this example below, I will demonstrate how to add new asset called "dog" to our AssetBundle named "animals" and build it then load it during run-time.
Setting Up Build Folders:
1. Select the asset such as image file. In this case, that's the "dog.jpeg" file. See the menu in the "Inspector" tab. Sometimes, the AssetBundle option it is hidden, drag it up to show it. See the animated gif below for how to do this. The default AssetBundle is "None". Click on the "None" option then go to the "New" option and create new AssetBundle and name it "animals"
2. Create a folder named StreamingAssets in the Assets folder. This is the folder we are going to build the AssetBundle into. Spelling counts and it's case sensitive so make sure to name it correctly.
3. Create sub-folder in the StreamingAssets folder to hold the AssetBundle. For this example, name this folder AssetBundles so that you can use it to recognize what's in it.
Building AssetBundle:
4. Below is the build script.
A. Create a script named ExportAssetBundles and put it in a folder named "Editor" in the Assets folder then copy the code below inside it:
using System.IO;
using UnityEditor;
using UnityEngine;
public class ExportAssetBundles
{
[MenuItem("Assets/Build AssetBundle")]
static void ExportResource()
{
string folderName = "AssetBundles";
string filePath = Path.Combine(Application.streamingAssetsPath, folderName);
//Build for Windows platform
BuildPipeline.BuildAssetBundles(filePath, BuildAssetBundleOptions.None, BuildTarget.StandaloneWindows64);
//Uncomment to build for other platforms
//BuildPipeline.BuildAssetBundles(filePath, BuildAssetBundleOptions.None, BuildTarget.iOS);
//BuildPipeline.BuildAssetBundles(filePath, BuildAssetBundleOptions.None, BuildTarget.Android);
//BuildPipeline.BuildAssetBundles(filePath, BuildAssetBundleOptions.None, BuildTarget.WebGL);
//BuildPipeline.BuildAssetBundles(filePath, BuildAssetBundleOptions.None, BuildTarget.StandaloneOSX);
//Refresh the Project folder
AssetDatabase.Refresh();
}
}
B. Build your AssetBudle by going to Assets --> Build AssetBundle menu.
You should see the built AssetBundles inside the Assets/StreamingAssets/AssetBundles directory. If not, refresh the Project tab.
Loading the AssetBundle during run-time:
5. When loading it, Application.streamingAssetsPath should be used to access the StreamingAssets folder. To access all the folders use, Application.streamingAssetsPath + "/AssetBundle/" + assetbunlenameWithoutExtension;. The AssetBundle and AssetBundleRequest API are used to load the AssetBundle. Since this is an image, Texture2D is passed to them. If using a prefab, pass GameObject instead then instantiate it. See comment in code for where these changes should be made. It is recommended to use Path.Combine to combine path names so the code below should use that instead.
Below is a simple loading function:
IEnumerator LoadAsset(string assetBundleName, string objectNameToLoad)
{
string filePath = System.IO.Path.Combine(Application.streamingAssetsPath, "AssetBundles");
filePath = System.IO.Path.Combine(filePath, assetBundleName);
//Load "animals" AssetBundle
var assetBundleCreateRequest = AssetBundle.LoadFromFileAsync(filePath);
yield return assetBundleCreateRequest;
AssetBundle asseBundle = assetBundleCreateRequest.assetBundle;
//Load the "dog" Asset (Use Texture2D since it's a Texture. Use GameObject if prefab)
AssetBundleRequest asset = asseBundle.LoadAssetAsync<Texture2D>(objectNameToLoad);
yield return asset;
//Retrieve the object (Use Texture2D since it's a Texture. Use GameObject if prefab)
Texture2D loadedAsset = asset.asset as Texture2D;
//Do something with the loaded loadedAsset object (Load to RawImage for example)
image.texture = loadedAsset;
}
Things to before loading note:
A. Name of Assetbundle is animals.
B. Name of the asset/object we want to load from the animals Assetbundle is dog This is a simple jpg of a dog.
C. The loading is simple as this:
string nameOfAssetBundle = "animals";
string nameOfObjectToLoad = "dog";
public RawImage image;
void Start()
{
StartCoroutine(LoadAsset(nameOfAssetBundle, nameOfObjectToLoad));
}
I have a suggestion as well that might be more accommodating to developers like me who want something more .Net based. You might consider building a "Launcher" using Unity. I would build it using Unity so it remains cross platform. Next, consider bundling your updates in a DLL since Unity supports .Net framework or store them as a image in a web folder. You can grab your data using Webclient. Article here:
https://learn.microsoft.com/en-us/dotnet/api/system.net.webclient.downloadfile?view=netframework-4.8#System_Net_WebClient_DownloadFile_System_Uri_System_String_
A launcher might be a better way to grab or update your content. I've been toying with the idea every since I played Lord of the Rings Online and I like their Launcher. So I wanted to make one for my own games. In your code you would use "DownloadFile(Uri, String)" to get your data. I would use an API or something to first check your current version of the game or DLL etc. Then check the data base for laest version. Finally the API or something could build a list of new files needed or updated files needed and just loop through requesting the files and download what you need.

Issue with AssetBundles, and reading serialized values at runtime

I have a set of Asset Bundles that I load prefabs from. I don't simulate Asset Bundles in the editor, and when the Asset Bundles are downloaded from the website in the editor, the scripts and serialzed values work as expected.
However, when I actually make a WebGL build that uses those same Asset Bundles (also built for WebGL) and upload it, the prefabs all appear correct, but the info attached to them using Serializable fields of a MonoBehavior are all set to their default values. Am I missing some sort of flag for my Asset Bundle building or something?
The first time I ran into this issue (for my menu system) I went ahead and serialized the data to JSON to load later, but for this situation I don't view that as a viable solution.
The prefabs are models of metal parts, and said metal parts all have a specific ID (which is an int) which I use to represent the part.
I have cleared my cache in my test browser (firefox) and I am running in a private tab to prevent any data being saved between test sessions. I am sure that the asset bundles are being re-acquired properly as it takes about 4 eternities to download them on the internet I am on here.
public class PartInfo : MonoBehaviour
{
[SerializeField]
public float Length;
[SerializeField]
public string Sku;
[SerializeField]
public int Id;
void OnValidate()
{
if (Sku == "")
{
Sku = gameObject.name.ToLower();
}
}
}
and
public void AddItem(GameObject go)
{
PartInfo goInfo = go.GetComponent<PartInfo>();
Debug.Log($"Found info attatched to part! {goInfo} with values {goInfo.Sku}, {goInfo.Id}, and {goInfo.Length}!!");
}
EDIT:
I forgot to mention, this is the editor script I use to build the Asset Bundles:
[MenuItem("Assets/Create Asset Bundles")]
static void ExportBundle()
{
BuildPipeline.BuildAssetBundles(Application.dataPath + #"/../AssetBundles", BuildAssetBundleOptions.None, BuildTarget.WebGL);
}
I expect the same output I get in the editor:
Found info attatched to part! SHILT5(Clone) (PartInfo) with values shilt5, 406, and 7!!
To show in the Web GL build:
Found info attatched to part! with values , 0, and 0!!
(Filename: ./Runtime/Export/Debug/Debug.bindings.h Line: 48)
EDIT: I went ahead and updated Unity today, but it didn't help anything. I'm doing a non-stripped dev/debug build to see if I can figure anything out.

Visual Studio stops debugging unity project

Setup: Unity 2017.4.16f1 / 2018.2.18f1
I've got an own written C# library, using .Net. The library works fine in a Winforms application. In general it contacts a server application and fetches some data.
Now we want to visualize the data within Unity. For that I followed this guide: https://docs.unity3d.com/Manual/UsingDLL.html. In short: Drag and drop the library in the asset folder, add a new script and access the library. My first problem was the compatibility. Because, I used Unity 2017.4.16f1 first, I needed to downgrade the library from .Net 4.7.2 to .Net 4.6 and change the project settings to the same .Net framework. After getting rid of all the compiler errors, I ran into my current Problem.
I attached Visual Studio 2017to unity set up my breakpoint and started the app within Unity. The breakpoint is on the first call of a function from my custom library. The breakpoint is reached. But if i say 'Step over' (either via click or F10) the active line doesn't switch and I get back to Unity. It's like i never started debugging. Unity goes on like nothing happened.
After that i tried it with Unity 2018.2.18f1. However, there is the same problem. The library isn't called.
Regarding some compatibility issues, I built the Unity project. No error occurs. Finally I stripped down the external library to a basic level. But again I got this strange behavior. Below is the script for unity and an example class from the custom library. Thank you for every advice.
C#:
[Serializable]
public class PostgreSQLParameters
[XmlElement(ElementName = "PostgreSQL_User", IsNullable = false)]
public string UserName
{
get
{
return this.userName;
}
set
{
if (this.userName == value)
return;
this.userName = value;
this.OnPropertyChanged();
}
}
public PostgreSQLParameters()
{ }
Unity:
void Start () {
string cwd = Directory.GetCurrentDirectory();
string pathVariable = Environment.GetEnvironmentVariable("PATH");
try
{
//this line has the break point, untill here all is ok
//after the Debug steps in, I hit F10 here to get to the next line,
//which should be the bracket befor the catch
PostgreSQLParameters parameter = new PostgreSQLParameters();
} // The cursor should be here after hitting F10, but disappears only
catch (Exception)
{
throw;
}
}
The core problem are the dependencies. I compared the dependencies in my library, with them from the unity project within Visual Studio. It turns out on library wasn't linked in Unity: System.Data.DataSetExtension. There are two solutions:
A) If you don't need them, omit them in your library. Delete the reference in the library and compile again
B) Or if you need them and it's part of '.Net' do the following (not tested):
See https://learn.microsoft.com/en-us/visualstudio/cross-platform/unity-scripting-upgrade?view=vs-2017#adding-assembly-references-when-using-the-net-4x-api-compatibility-level
add a file, called mcs.rsp, in the asset root
Insert the line -r:System.Data.DataSetExtension (take the name of the reference you need)
Restart Unity

Copy some extra file in data folder after build in unity

I have to copy two text files and a folder to my build data folder after finishing the build (exe) for windows platform. Each time I build, I want to copy these files and folder from assets to build data folder. Is this possible in unity? Cause sometime I forget to copy desired file in data folder and my player does not work correctly.
You can subscribe a static method to PostprocessBuild.OnPostprocessBuild
This method will be called every time a build is finished.
So your code might look like this:
using UnityEditor;
using System.IO;
using UnityEditor.Build;
using UnityEngine;
class MyCustomBuildProcessor : IPostprocessBuild
{
public int callbackOrder { get { return 0; } }
public void OnPostprocessBuild(BuildTarget target, string path)
{
File.Copy("sourceFilePath","destinationFilePath");
}
}
It sounds like you want your own custom editor build function. You can do this with a custom editor menu item.
Unity Editor Extensions – Menu Items
Here is what the code might look like:
[MenuItem("MyBuildMenu/MyBuildMenuItem")]
static void BuildAndCopyItems()
{
File.Copy("path1","path2"); // copy your files
BuildPipeline.BuildPlayer(); // build the player
}
you'll need to pass the correct arguments to BuildPlayer:
BuildPipeline.BuildPlayer
The file containing this script will need to be within your project in a folder called 'Editor'.
And you'll get a new menu item in the Unity editor to perform your custom build:

Categories

Resources