Failed to decompress data for the AssetBundle 'Memory'. -- Unity3D AssetBundle Loading - unity3d

IEnumerator WWWLoader()
{
WWW bundleRequest = new WWW("*****************");
while(!bundleRequest.isDone)
{
yield return null;
}
AssetBundle bundle = null;
if (bundleRequest.bytesDownloaded > 0)
{
AssetBundleCreateRequest myRequest = AssetBundle.LoadFromMemoryAsync(bundleRequest.bytes);
while(!myRequest.isDone)
{
Debug.Log("loading....");
yield return null;
}
if (myRequest.assetBundle != null)
{
bundle = myRequest.assetBundle;
GameObject model = null;
if (bundle != null)
{
AssetBundleRequest newRequest = bundle.LoadAssetAsync<GameObject>("Log");
while (!newRequest.isDone)
{
Debug.Log("loading ASSET....");
yield return null;
}
model = (GameObject)newRequest.asset;
bundle.Unload(false);
}
}
else
{
Debug.LogError("COULDN'T DOWNLOAD ASSET BUNDLE FROM URL (assetBundle = null)");
}
}
else
{
Debug.LogError("COULDN'T DOWNLOAD ASSET BUNDLE FROM URL (0 bytes)");
}
}
This is my code to load an AssetBundle (I've removed the URL). It gives me the error "Failed to decompress data for the AssetBundle 'Memory'." I'm not sure if 'Memory' is referring to the AssetBundle name because mine is called 'log' so is it referring to a problem with memory? Any help on understanding this error and fixing it is much appreciated.

I believe your issue related to the compression being used when the bundles are built. You may need to use LoadFromMemoryAsync instead. https://docs.unity3d.com/ScriptReference/AssetBundle.LoadFromMemoryAsync.html

So, I have gotten past the error by using UnityWebRequestAssetBundle as shown here (recommended by derHugo).
I was initially using a simple FTP server to access the assets and it would not allow me to download them (from Unity, but in a browser it worked fine). I then switched to using a Flask server, which worked like a charm.

Note to people finding this like I did; if you're using Asset Bundles for webgl, you need to make sure the assetbundles are uncompressed (BuildAssetBundleOptions.UncompressedAssetBundle). Docs mention it but it can be easy to miss, and the default is LZMA.

Related

How to save/share a file in Net. Maui without savefiledialog?

My MauiBlazorApp can create a .pdf file. In what ways can I make this file accessible for the users of windows/android/IOS. A SaveFile Dialog is not yet implemented in Maui. With this path
string SaveToPath = System.IO.Path.Combine(FileSystem.Current.AppDataDirectory, "hello.pdf");
I can save it on a windows machine and open it (tested).
The path (FileSystem.Current.AppDataDirectory) on a local android device (phone connected to windows maschine via usb) is something like this:
/data/user/0/com.companyname.appname/files/hello.pdf
But later I can't find this folder on my phone. I find this:
/data/com.companyname.appname/cache/ empty folders all the way
Why can't I save a file in .../downloads
How do you import/export data from 'device to device' in Maui? Files seems to be not the way. Email with attechments? Is that possible/better?
You can check the Maui File picker, It provides the method you can pick the file from the device.
public async Task<FileResult> PickAndShow(PickOptions options)
{
try
{
var result = await FilePicker.Default.PickAsync(options);
if (result != null)
{
if (result.FileName.EndsWith("jpg", StringComparison.OrdinalIgnoreCase) ||
result.FileName.EndsWith("png", StringComparison.OrdinalIgnoreCase))
{
using var stream = await result.OpenReadAsync();
var image = ImageSource.FromStream(() => stream);
}
}
return result;
}
catch (Exception ex)
{
// The user canceled or something went wrong
}
return null;
}
In addition, you can refer to Folder Picker .NET MAUI. This is more detailed.

Play game saves ((PlayGamesPlatform)Social.Active).SavedGame.OpenWithAutomaticConflictResolution doesn't invoke save function

Good day!
I am new to Google Play Services and want to save JSON(string) into the cloud and it doesn't work. I narrowed down a problem through phone and debug texts and realized that a function from ((PlayGamesPlatform)Social.Active).SavedGame.OpenWithAutomaticConflictResolution is not called which is strange because in the tutorial that I watched everything worked and the user logged in successfuly.
here is a code snippet with a comments and a function that is not invoked(I can send a whole script if needed also). Is there something else I am missing?
public void OpenSaveToCloud(bool saving)
{
// debugtext.text = "hello";
if(Social.localUser.authenticated)
{
debugtext.text = "Authorized and proceed to save";
issaving = saving;
((PlayGamesPlatform)Social.Active).SavedGame.OpenWithAutomaticConflictResolution
(SAVE_NAME, GooglePlayGames.BasicApi.DataSource.ReadCacheOrNetwork,
ConflictResolutionStrategy.UseLongestPlaytime, SavedGameOpen); //SavedGame open must be called
}
else{
debugtext.text = "No authentication";
}
}
private void SavedGameOpen(SavedGameRequestStatus status, ISavedGameMetadata meta)//this function is not called
{
if(status == SavedGameRequestStatus.Success)
{
// debugtext.text = "hello in save1";
if (issaving)//if is saving is true we are saving our data to cloud
{
debugtext.text = "Saving....";
byte[] data = System.Text.ASCIIEncoding.ASCII.GetBytes(GetDataToStoreinCloud());
SavedGameMetadataUpdate update = new SavedGameMetadataUpdate.Builder().Build();
((PlayGamesPlatform)Social.Active).SavedGame.CommitUpdate(meta, update, data, SaveUpdate);
}
else//if is saving is false we are opening our saved data from cloud
{
debugtext.text = "Loading...";
((PlayGamesPlatform)Social.Active).SavedGame.ReadBinaryData(meta, ReadDataFromCloud);
}
}
else{
debugtext.text = "Save request status broke";
}
}
What I checked twice before posting question:
Turned on Saved Games in google console
made build with your keystore and password
add email id in game service's tester section
Mistake is that you have to initialize save games from start as well and I didn't know that so answer would be
if (platform == null)
{
PlayGamesClientConfiguration config = new PlayGamesClientConfiguration.Builder().EnableSavedGames().Build();
PlayGamesPlatform.InitializeInstance(config);
PlayGamesPlatform.DebugLogEnabled = true;
platform = PlayGamesPlatform.Activate();
}

not able to download file with size more than 63kb using UnityWebRequest

i am try to download asset bundle from an url but the request keep on cancelling after downloading 63kb. Can anyone explain to me why this may be happening?
My Code :
public IEnumerator DL()
{
string downloadlink = "https://drive.google.com/file/d/1OGyrB4-MQfo-HVom9ENvV4dn312_wL4Q/view?usp=sharing";
string filepath = Application.persistentDataPath + "/electroplatingNN";
//Download
UnityWebRequest dlreq = new UnityWebRequest(downloadlink);
dlreq.downloadHandler = new DownloadHandlerFile(filepath);
dlreq.timeout = 15;
UnityWebRequestAsyncOperation op = dlreq.SendWebRequest();
while (!op.isDone)
{
//here you can see download progress
Debug.Log(dlreq.downloadedBytes / 1000 + "KB");
yield return null;
}
if (dlreq.isNetworkError || dlreq.isHttpError)
{
Debug.Log(dlreq.error);
}
else
{
Debug.Log("download success");
}
dlreq.Dispose();
yield return null;
}
As already mentioned in the comments the issue is not in the UnityWebrequest but rather Google Drive doesn't simply download your file as you expect.
Instead the data you download is actually only the web page which would allow you to download it. If I simply open your file in a browser I get a page looking like this
where I now could download your file.
There are packages like this or this which implement the necessary stuff for actually download files from Google Drive API in Unity.

Load object from Asset Bundle

I have Download and Main cs files. The first one contains method LoadAsset
public IEnumerator LoadAsset(string link, string loadObject)
{
WWW download;
string ErrorMsg=" ";
download = new WWW(link);
yield return download;
if (download.error != null)
{
ErrorMsg=download.error;
}
else
{
ErrorMsg="Downloading ....";
AssetBundle asset = download.assetBundle;
GameObject loadedObject;
loadedObject = Instantiate(asset.Load(loadObject,typeof(GameObject))) as GameObject;
asset.Unload(false);
ErrorMsg="Done";
}
Debug.Log(ErrorMsg);
}
I want to call this method from Main.cs file and return loadedObject in it. Tried to use StartCoroutine
Download download;
download=new Download();
StartCoroutine("download.LoadAsset()");
but without success. Can anybody help me?
Try without the quotes
StartCoroutine( download.LoadAsset() )
You add the quotes when you want to cancel it, but it won't work on a method outside your class.
It would be event better to add a method to your Main.cs that starts the coroutine for you, something like this
public void StartLoadAssetCo()
{
StartCoroutine(LoadAsset());
}
and then just call StartLoadAssetCo from outside the class
download.StartLoadAssetCo();

Need to scan WEB-INF/lib/xxx-ejb.jar for Type and Method annotations

I want to do the following using Google Reflections:
Scan only WEB-INF/lib/Patrac-ejb.jar
Scan only the package com.patrac and all of its sub-packages.
Scan for only type- and method annotations.
The following configuration seems to work fine but I don't have any experience with Google Reflections.
Reflections reflections = new Reflections(
new ConfigurationBuilder()
.filterInputsBy(new FilterBuilder().include("Patrac-ejb.jar").include(FilterBuilder.prefix("com.patrac")))
.setScanners(new MethodAnnotationsScanner(), new TypeAnnotationsScanner())
.setUrls(ClasspathHelper.forWebInfLib(servletContext))
);
It appears to be working. I want to make sure it's not scanning all the other JARs in WEB-INF/lib. Is there an easy way to discover what JARs are being matched by the filter inputs in the configuration? Any advice about my approach would be much appreciated.
The following worked:
// Get the URL for Patrac-ejb.jar:
Set<URL> urls = ClasspathHelper.forWebInfLib(webUtil.getServletContext());
URL patracJarUrl = null;
for(URL url : urls)
{
if(url.getFile().endsWith("Patrac-ejb.jar"))
{
patracJarUrl = url;
break;
}
}
if(null == patracJarUrl)
{
throw new IllegalStateException("Patrac-ejb.jar not found.");
}
// Add the Patrac-ejb.jar URL to the configuration.
Configuration configuration = new ConfigurationBuilder()
.filterInputsBy(new FilterBuilder()
.include(FilterBuilder.prefix("com.patrac")))
.setScanners(new MethodAnnotationsScanner(), new TypeAnnotationsScanner())
.setUrls(patracJarUrl);