Technical Help Needed Integrating UMA into DFU
- MasonFace
- Posts: 543
- Joined: Tue Nov 27, 2018 7:28 pm
- Location: Tennessee, USA
- Contact:
Re: Technical Help Needed Integrating UMA into DFU
Well, I was never able to get UMA version 2.9 to compile into an assembly. I reached out to the UMA dev team and they said that the error I was getting was due to a bug and that it's fixed in UMA 2.10. So I upgraded and was able to get it to compile without any problems.
Unfortunately, UMA 2.10 requires .NET 4.0... so that won't work with DFU at the moment.
I won't let that stop me from developing, though. I'll keep working with UMA 2.9, then upgrade it to 2.10 once DFU gets upgraded to Unity 2019.4 LTS and .NET4.7.1.
Most of the work of this mod will be clothing/hair models and animations anyhow, so I probably wouldn't have enough assets to release a mod until late Spring anyway.
Unfortunately, UMA 2.10 requires .NET 4.0... so that won't work with DFU at the moment.
I won't let that stop me from developing, though. I'll keep working with UMA 2.9, then upgrade it to 2.10 once DFU gets upgraded to Unity 2019.4 LTS and .NET4.7.1.
Most of the work of this mod will be clothing/hair models and animations anyhow, so I probably wouldn't have enough assets to release a mod until late Spring anyway.
- Azteca
- Posts: 143
- Joined: Tue Mar 26, 2019 12:38 am
Re: Technical Help Needed Integrating UMA into DFU
Awesome news, Mason. Thanks for keeping us posted. So you’ll have to do some waiting to share it with others but it sounds like this is still a very feasible project. I’ll be paying attention!
- MasonFace
- Posts: 543
- Joined: Tue Nov 27, 2018 7:28 pm
- Location: Tennessee, USA
- Contact:
Re: Technical Help Needed Integrating UMA into DFU
@TheLacus:
I'm having some trouble understanding exactly when the SetPerson method gets called on a MobliePersonAsset.
What is controlling the assignment of the race, gender, variant, and isGuard arguments?
My assumption was that the PopulationManager would assign all of these parameters to the MobileNPC upon initialization, but it doesn't look like that's where the assignment comes from after all.
The reason I ask is because it doesn't seem like the SetPerson method in my MobilePersonCube (yeah, I never renamed it from your example script) is consistently firing off. For debug purposes, I'm renaming the MobilePersonAsset inside the SetPerson method to take on the name in the format of Race Gender Variant (i.e. BretonFemale3), but not all instances of MobilePersonAsset are getting their name reassigned. Likewise, any other code I've put in the SetPerson method is not being ran.
If from the Unity Editor I use the "Apply Person Type" on the MobileNPC game object, then it will force it to update and successfully run all the SetPerson code, but of course it sets the race/gender/variant data to whatever was chosen in the inspector.
I'm not sure if it is important or not, but I'm having to delay getting the MeshRenderer because UMA requires a few miliseconds to create the mesh at runtime.
Is there a way to just force SetPerson to refresh its original assignment?
As a related followup questions, where do the portrait assignments come from? I'm just asking in case I want to later expand the MobilePersonAsset to have a face that matches their portrait.
I'm having some trouble understanding exactly when the SetPerson method gets called on a MobliePersonAsset.
What is controlling the assignment of the race, gender, variant, and isGuard arguments?
My assumption was that the PopulationManager would assign all of these parameters to the MobileNPC upon initialization, but it doesn't look like that's where the assignment comes from after all.
The reason I ask is because it doesn't seem like the SetPerson method in my MobilePersonCube (yeah, I never renamed it from your example script) is consistently firing off. For debug purposes, I'm renaming the MobilePersonAsset inside the SetPerson method to take on the name in the format of Race Gender Variant (i.e. BretonFemale3), but not all instances of MobilePersonAsset are getting their name reassigned. Likewise, any other code I've put in the SetPerson method is not being ran.
If from the Unity Editor I use the "Apply Person Type" on the MobileNPC game object, then it will force it to update and successfully run all the SetPerson code, but of course it sets the race/gender/variant data to whatever was chosen in the inspector.
I'm not sure if it is important or not, but I'm having to delay getting the MeshRenderer because UMA requires a few miliseconds to create the mesh at runtime.
Is there a way to just force SetPerson to refresh its original assignment?
As a related followup questions, where do the portrait assignments come from? I'm just asking in case I want to later expand the MobilePersonAsset to have a face that matches their portrait.
- TheLacus
- Posts: 1305
- Joined: Wed Sep 14, 2016 6:22 pm
Re: Technical Help Needed Integrating UMA into DFU
PopulationManager handles a pool of npcs which are assigned a random race and gender and eventually recicled when outside player's field of view. I don't think there is necessarily something wrong if some npcs are not being assigned immediately.
But i wouldn't worry about this right now. It shouldn't affect core functionalities so this is something we can improve later if needed.
MeshRenderer is accessed by PopulationManager here:
Code: Select all
// Do not render active mobile until it has made at least 1 full tile move
// This hides skating effect while unit aligning to navigation grid
if (poolItem.active && poolItem.npc.Asset)
{
MeshRenderer billboardRenderer = poolItem.npc.Asset.GetComponent<MeshRenderer>();
if (billboardRenderer)
billboardRenderer.enabled = (poolItem.npc.Motor.MoveCount > 0) ? true : false;
}
I'm not sure i understand, can you elaborate? If the issue is the MeshRender delay you can wait for it with a Coroutine. You can start it from SetPerson and pass all parameters required to setup the mesh after you have waited for it asynchronously.
- TheLacus
- Posts: 1305
- Joined: Wed Sep 14, 2016 6:22 pm
Re: Technical Help Needed Integrating UMA into DFU
Here's an example if it can be helpful.
Code: Select all
public override void SetPerson(Races race, Genders gender, int personVariant, bool isGuard)
{
StartCoroutine(SetPersonAsync(race, gender, personVariant, isGuard));
}
private IEnumerator SetPersonAsync(Races race, Genders gender, int personVariant, bool isGuard)
{
// Wait for MeshRenderer.
// If you have a better way to know when UMA has finished is better...
float timeout = 3;
MeshRenderer meshRenderer = null;
while (!meshRenderer && timeout > 0)
{
yield return null;
meshRenderer = GetComponent<MeshRenderer>();
timeout -= Time.unscaledDeltaTime;
}
// do something with MeshRenderer
}
- TheLacus
- Posts: 1305
- Joined: Wed Sep 14, 2016 6:22 pm
Re: Technical Help Needed Integrating UMA into DFU
TalkManager:
Code: Select all
DaggerfallUI.Instance.TalkWindow.SetNPCPortrait(DaggerfallTalkWindow.FacePortraitArchive.CommonFaces, targetMobileNPC.PersonFaceRecordId);
Code: Select all
// get face record id to use (randomize portrait for current person outfit variant)
int personFaceVariant = Random.Range(0, numPersonFaceVariants);
this.personFaceRecordId = recordIndices[personOutfitVariant] + personFaceVariant;
// set billboard to correct race, gender and outfit variant
Asset = GetComponentInChildren<MobilePersonAsset>();
Asset.SetPerson(race, gender, personOutfitVariant, IsGuard);
- MasonFace
- Posts: 543
- Joined: Tue Nov 27, 2018 7:28 pm
- Location: Tennessee, USA
- Contact:
Re: Technical Help Needed Integrating UMA into DFU
Thank you for the responses. That does help clarify a few things for me, but I'm still a little stuck.
The crux of my problem is that SetPerson doesn't seem to be initializing consistently. I've tried delaying the SetPerson using "Invoke" and added some delays using Coroutines, and that helped to a large degree, but most of the NPCs are acting as if their SetPerson method is never even getting called.
In my SetPerson code, I have it set so that the name of the MobilePersonAsset game object will change its name based on its Race, Gender, and Variant. It will also change its gender and set its height to the max value of 1 (very tall). But what's actually happening is that only some of them are getting their names changes, and only some are getting their heights changed.
For debug purposes, I've set my "H" key to call SetPerson with race = breton, gender = female, variant = 1, and isGuard = false. When I press "H", it does properly set all the MobileNPCs to very tall Breton Females, but of course I don't want all the villagers to be Amazon women; I'd rather they maintain their vanilla assignments.
So how do I get SetPerson to work consistently? Am I supposed to call it in my code somewhere? If so, am I supposed to randomize the override arguments? Am I approaching this totally wrong?
I hope this makes sense.
Note that I'm currently setting the return of GetSize() to a constant Vector3 of (1, 2, 1); I'll fix that later.
Also note that UMA distinguishes male and female archetypes as different "races". They use very misleading terminology...
Code below:
The crux of my problem is that SetPerson doesn't seem to be initializing consistently. I've tried delaying the SetPerson using "Invoke" and added some delays using Coroutines, and that helped to a large degree, but most of the NPCs are acting as if their SetPerson method is never even getting called.
In my SetPerson code, I have it set so that the name of the MobilePersonAsset game object will change its name based on its Race, Gender, and Variant. It will also change its gender and set its height to the max value of 1 (very tall). But what's actually happening is that only some of them are getting their names changes, and only some are getting their heights changed.
For debug purposes, I've set my "H" key to call SetPerson with race = breton, gender = female, variant = 1, and isGuard = false. When I press "H", it does properly set all the MobileNPCs to very tall Breton Females, but of course I don't want all the villagers to be Amazon women; I'd rather they maintain their vanilla assignments.
So how do I get SetPerson to work consistently? Am I supposed to call it in my code somewhere? If so, am I supposed to randomize the override arguments? Am I approaching this totally wrong?
I hope this makes sense.
Note that I'm currently setting the return of GetSize() to a constant Vector3 of (1, 2, 1); I'll fix that later.
Also note that UMA distinguishes male and female archetypes as different "races". They use very misleading terminology...
Code below:
Spoiler!
- TheLacus
- Posts: 1305
- Joined: Wed Sep 14, 2016 6:22 pm
Re: Technical Help Needed Integrating UMA into DFU
Can you try to disable colliders and see if it makes any difference? I suspect they might interfer with MobilePersonMotor.IsDirectionClear() and cause them to be stuck in place.
I can confirm that you don't need to call SetPerson(), what you're doing now seems to be fine.
EDIT: yes, broken with commit prevent mobile NPCs from entering stairs.
I can confirm that you don't need to call SetPerson(), what you're doing now seems to be fine.
EDIT: yes, broken with commit prevent mobile NPCs from entering stairs.
- MasonFace
- Posts: 543
- Joined: Tue Nov 27, 2018 7:28 pm
- Location: Tennessee, USA
- Contact:
Re: Technical Help Needed Integrating UMA into DFU
Okay, thank you for looking into that! It was driving me crazy trying to figure out what was going on.
- TheLacus
- Posts: 1305
- Joined: Wed Sep 14, 2016 6:22 pm
Re: Technical Help Needed Integrating UMA into DFU
@MasonFace would it work for you if we use a layer mask to ignore colliders on npcs? I understand that you are using multiple layers, so this mask could be provided by the implementation at runtime if needed.