Hi! If you want to save time and still help please read this section and the last one to get glimpse of my problem (part 1 and 6). So much code was needed to fully present problem
Using Unity 2019.3.0b2
1.
Im creating WebGL application that allows you to customize your character via assets from downloaded asset bundles. So far I got downloading and instantiating work, but I also want to change downloaded gameobject material to custom color from color-picker. In this case I need to refer to adequate Renderer. I've got function that sends request and it goes like so:
private IEnumerator SendRequestCoroutine(UnityWebRequest request, UnityAction<UnityWebRequest> OnDownloadCompleteHandler, UnityAction<float> OnDownloadProgressHandler = null)
{
request.SendWebRequest();
while(!request.isDone)
{
if(OnDownloadProgressHandler != null)
OnDownloadProgressHandler.Invoke(request.downloadProgress);
yield return null;
}
// Has to fire once more because progress stops at around 0.87,
// never returning 1 unless download is finished.
if (OnDownloadProgressHandler != null)
OnDownloadProgressHandler.Invoke(1);
OnDownloadCompleteHandler.Invoke(request);
}
2. I fire this coroutine like that:
public void DownloadAssetBundle(string url, ProgressBar bar = null)
{
if (isRequestSend)
{
Alerter.ShowMessage("Request has been already send, please wait untill complete.");
return;
}
UnityWebRequest request = HttpService.Instance.GetAssetBundleRequest(url);
if(bar != null)
{
HttpService.Instance.SendDownloadRequest
(
request,
(rq) => { OnDownloadAssetBundleCompleteHandler(rq); },
(rq) => OnDownloadProgressHandler(rq, bar)
);
isRequestSend = true;
}
else
{
HttpService.Instance.SendDownloadRequest
(
request,
(rq) => { OnDownloadAssetBundleCompleteHandler(rq); }
);
isRequestSend = true;
}
}
3. OnDownloadAssetBundleCompleteHandler looks like this:
//Function that will handle asset bundle when completed.
private void OnDownloadAssetBundleCompleteHandler(UnityWebRequest request)
{
isRequestSend = false;
if(request.isHttpError || request.isNetworkError)
{
//Handle downloading error
Alerter.ShowMessage("Seems like there was a problem with downloading, try again.");
}
else
{
AssetBundle bundle;
//Handle content update
bundle = DownloadHandlerAssetBundle.GetContent(request);
AssetBundleInfo assetBundleInfo = bundle.LoadAllAssets<AssetBundleInfo>().FirstOrDefault();
if (assetBundleInfo == null)
{
//Handle error
Alerter.ShowMessage("Couldn't read information about this Character Part. AssetBundleInfo null exception.");
bundle.Unload(false);
return;
}
GameObject goToLoad = null;
goToLoad = bundle.LoadAsset<GameObject>(assetBundleInfo.ObjectName);
if (goToLoad == null)
{
Alerter.ShowMessage("Couldn't read information about this Character Part. Downloaded asset's gameobject null exception.");
bundle.Unload(false);
return;
}
Sticher.ConnectComponent(goToLoad, assetBundleInfo.PartType);
ColorSetter.Instance.ChangeSelectedBodyPart(assetBundleInfo.PartType);
bundle.Unload(false);
}
}
4. Now the final step is to set adequate transform so my script will search for component of type Renderer, get its material of index 0 as current material to modify, class that contain ChangeSelectedBodyPart function looks like so:
using Assets.Scripts.Models.Enums;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ColorSetter : MonoBehaviour
{
public Renderer rend;
public ColorPicker picker;
public static ColorSetter Instance;
private void Awake()
{
if(Instance != null)
{
Destroy(this);
}
else
{
Instance = this;
DontDestroyOnLoad(this);
}
}
// Start is called before the first frame update
void Start()
{
picker.onValueChanged.AddListener(color =>
{
if (rend == null)
return;
rend.material.SetColor("_BaseColor", color);
}
);
}
public void ChangeSelectedBodyPart(AvatarPartType p)
{
switch(p)
{
case AvatarPartType.ClothesUpper:
SetActiveMaterial(Sticher.Instance.Clothes_Upper);
break;
case AvatarPartType.ClothesLower:
SetActiveMaterial(Sticher.Instance.Clothes_Lower);
break;
case AvatarPartType.Shoes:
SetActiveMaterial(Sticher.Instance.Shoes);
break;
case AvatarPartType.Hair:
SetActiveMaterial(Sticher.Instance.Hair);
break;
case AvatarPartType.Skin:
SetActiveMaterial(Sticher.Instance.Skin);
break;
}
}
private void SetActiveMaterial(Transform parent)
{
rend = parent.GetComponentInChildren<Renderer>();
}
}
5. PS. parent has only one child that contains Renderer component Now, finally, problem is that I don't get proper material reference, I got the old one that is being set via toggle button, simply as that:
public void OnValueChanged(bool value)
{
if(value)
{
ColorSetter.Instance.ChangeSelectedBodyPart(PartType);
ButtonManager.Instance.RemoveAllButtonsFromPartsWindow();
ButtonManager.Instance.PopulatePartsPanelWithAvatarPartsOfType(PartType);
}
}
6. So in conclusion when I press on "toggle button" that represents some avatar body/clothing part it sets its parent and material properly via function, even after asset bundle has been downloaded (but I have to click the same toggle again to make it work), but when I fire the same function in OnDownloadAssetBundleCompleteHandler just after asset been downloaded it doesn't work :S Why? Is it related with asset unloading speed? Any tips on fixing this?