123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264 |
- using System.Collections;
- using System.Collections.Generic;
- using UnityEngine;
- using Sirenix.OdinInspector;
- using System;
- using System.Linq;
- using UnityEngine.Assertions;
- using NodeCanvas.Framework;
- using KairoEngine.Core;
- using KairoEngine.Inventory;
- namespace KairoEngine.CharacterSystem
- {
- public class CharacterGenerator : MonoBehaviour
- {
- public static CharacterGenerator instance;
- public GameObject characterTemplatePrefab;
- [AssetList(Path = "/Data/Characters/ModelData/", AutoPopulate = true)]
- public List<ModelData> modelList;
-
- [AssetList(Path = "/Data/Characters/Attachments/", AutoPopulate = true)]
- public List<GameObject> attachmentList;
- void OnEnable()
- {
- GenericEvents.StartListening("GenerateCharacter", Create);
- }
- void OnDisable()
- {
- GenericEvents.StopListening("GenerateCharacter", Create);
- }
- void Awake()
- {
- if(instance == null) instance = this;
- else Destroy(this.gameObject);
- }
- public void Create(ScriptableObject scriptableObject)
- {
- CharacterData characterData = (CharacterData)scriptableObject;
- Create(characterData);
- }
- public static CharacterController Create(CharacterData data, Vector3 position, Quaternion rotation)
- {
- data.hasSpawned = true;
- data.position = position;
- data.rotation = rotation;
- return Create(data);
- }
- public static CharacterController Create(CharacterData data)
- {
- // Instantiate Template Character Prefab
- GameObject characterObj = GameObject.Instantiate(instance.characterTemplatePrefab, data.position, data.rotation);
- characterObj.name = "Character_" + data.characterName;
- CharacterController characterController = characterObj.GetComponentInChildren<CharacterController>();
- // Set Body Model
- ModelData modelData = FindModel(data.bodyModel);
- if(modelData == null)
- {
- Debug.LogError("No modelData found with name " + data.bodyModel, data);
- return null;
- }
- Material material = GetMaterialInModelData(modelData, data.bodyMaterial);
- SkinRigger skinRigger = characterObj.GetComponentInChildren<SkinRigger>();
- if(skinRigger == null) Debug.LogError("Missing SkinRigger component", characterObj);
- else skinRigger.Setup(modelData, material);
- // Set Head Attachment
- if(data.headAttachment != "")
- {
- GameObject headAttachmentPrefab = FindAttachment(data.headAttachment);
- if(headAttachmentPrefab != null) GameObject.Instantiate(headAttachmentPrefab, characterController.head.transform);
- }
- // Set Face Attachment
- if(data.faceAttachment != "")
- {
- GameObject faceAttachmentPrefab = FindAttachment(data.faceAttachment);
- if(faceAttachmentPrefab != null) GameObject.Instantiate(faceAttachmentPrefab, characterController.head.transform);
- }
- // Set Name
- characterController.characterName = data.name;
- characterController.id = data.id;
- // Set Faction
- characterController.faction = data.faction;
- // Set details
- characterController.race = data.race;
- characterController.gender = data.gender;
- characterController.age = data.age;
- // Set Visuals
- characterController.bodyModelName = data.bodyModel;
- characterController.bodyMaterialName = data.bodyMaterial;
- characterController.headAttachmentName = data.headAttachment;
- characterController.faceAttachmentName = data.faceAttachment;
- // Set Hitpoints and armor
- characterController.damageController.SetHP(data.hitpoints);
- characterController.damageController.SetMaxHP(data.maxHitpoints);
- characterController.damageController.SetArmor(data.armor);
- // Set inventory items
- ItemContainer itemContainer = characterController.GetComponent<ItemContainer>();
- for (int b = 0; b < data.itemList.Count; b++)
- {
- if(data.itemList[b].item.category == ItemType.firearm)
- {
- var originalFirearmRef = data.itemList[b] as ItemFirearmRef;
- if (originalFirearmRef == null)
- {
- ItemBaseFirearm itemBaseFirearm = (ItemBaseFirearm)data.itemList[b].item;
- ItemBaseAmmo itemBaseAmmo = (ItemBaseAmmo)itemBaseFirearm.ammoType;
- int ammo = itemBaseFirearm.ammoCapacity;
- ItemFirearmRef firearmRef = new ItemFirearmRef(itemBaseFirearm, data.itemList[b].quantity, itemBaseAmmo, ammo);
- itemContainer.AddItem(firearmRef);
- }
- else
- {
- ItemFirearmRef newFirearm = new ItemFirearmRef(data.itemList[b].item, data.itemList[b].quantity, originalFirearmRef.ammoType,
- originalFirearmRef.ammo, originalFirearmRef.accuracyModifier, originalFirearmRef.lastUsed);
- itemContainer.AddItem(newFirearm);
- }
-
- }
- else
- {
- ItemRef newItem = new ItemRef(data.itemList[b].item, data.itemList[b].quantity, data.itemList[b].lastUsed);
- itemContainer.AddItem(newItem);
- }
- }
- // Set Sensors
- if(characterController.visionSensor != null) characterController.visionSensor.enabled = data.vision;
- if(characterController.hearingSensor != null) characterController.hearingSensor.enabled = data.hearing;
- // Set death stance
- if(data.isDead)
- {
- characterController.Die();
- SetBones(data.bones, characterController);
- }
- // Set Dialogue
- Blackboard blackboard = characterController.GetComponent<Blackboard>();
- if(blackboard !=null && data.dialogueTree != null) blackboard.SetVariableValue("dialogueTree", data.dialogueTree);
- return characterController;
- }
- public static ModelData FindModel(string title)
- {
- for (int i = 0; i < instance.modelList.Count; i++)
- {
- if(instance.modelList[i] != null)
- {
- if(instance.modelList[i].name == title) return instance.modelList[i];
- }
-
- }
- return null;
- }
- public static Material GetMaterialInModelData(ModelData modelData, string materialName)
- {
- if(modelData != null)
- {
- for (int i = 0; i < modelData.materials.Count; i++)
- {
- if(modelData.materials[i].name == materialName) return modelData.materials[i];
- }
- }
- return null;
- }
- public static GameObject FindAttachment(string title)
- {
- for (int i = 0; i < instance.attachmentList.Count; i++)
- {
- if(instance.attachmentList[i].name == title) return instance.attachmentList[i];
- }
- return null;
- }
- public static void SetBones(List<DataBone> bones, CharacterController character)
- {
- int boneCount = 0;
- character.animator.enabled = false;
- Destroy(character.puppetMaster.gameObject);
- Transform[] transforms = character.transform.root.GetComponentsInChildren<Transform>();
- for (int i = 0; i < bones.Count; i++)
- {
- for (int a = 0; a < transforms.Length; a++)
- {
- if(bones[i].name == transforms[a].gameObject.name)
- {
- transforms[a].position = bones[i].position;
- transforms[a].rotation = bones[i].rotation;
- boneCount += 1;
- }
- }
- }
- Debug.Log($"Set up {boneCount}/{bones.Count} bones for {character.unique_name}");
- }
- public static void UpdateBoneOrder(SkinnedMeshRenderer meshRenderer)
- {
- Transform[] children = meshRenderer.rootBone.GetComponentsInChildren<Transform>();
- Transform[] bones = new Transform[meshRenderer.bones.Length];
- for (int boneOrder = 0; boneOrder < meshRenderer.bones.Length; boneOrder++)
- {
- bones[boneOrder] = Array.Find<Transform>(children, c => c.name == meshRenderer.bones[boneOrder].name);
- }
- meshRenderer.bones = bones;
- }
- public static void UpdateBoneOrder2(SkinnedMeshRenderer rend)
- {
- //list of bones
- List<Transform> tList = rend.bones.ToList();
-
- //sort alphabetically
- tList.Sort(CompareTransform);
-
- //record bone index mappings (richardf advice)
- //build a Dictionary<int, int> that records the old bone index => new bone index mappings,
- //then run through every vertex and just do boneIndexN = dict[boneIndexN] for each weight on each vertex.
- Dictionary<int, int> remap = new Dictionary<int, int>();
- for (int i = 0; i < rend.bones.Length; i++)
- {
- remap[i] = tList.IndexOf(rend.bones[i]);
- }
-
- //remap bone weight indexes
- BoneWeight[] bw = rend.sharedMesh.boneWeights;
- for (int i = 0; i < bw.Length; i++)
- {
- bw[i].boneIndex0 = remap[bw[i].boneIndex0];
- bw[i].boneIndex1 = remap[bw[i].boneIndex1];
- bw[i].boneIndex2 = remap[bw[i].boneIndex2];
- bw[i].boneIndex3 = remap[bw[i].boneIndex3];
- }
-
- //remap bindposes
- Matrix4x4[] bp = new Matrix4x4[rend.sharedMesh.bindposes.Length];
- for (int i = 0; i < bp.Length; i++)
- {
- var r = remap[i];
- if(bp.Length > r && rend.sharedMesh.bindposes.Length > i)
- {
- bp[r] = rend.sharedMesh.bindposes[i];
- }
-
- }
-
- //assign new data
- rend.bones = tList.ToArray();
- rend.sharedMesh.boneWeights = bw;
- rend.sharedMesh.bindposes = bp;
- }
-
- private static int CompareTransform(Transform A, Transform B)
- {
- return A.name.CompareTo(B.name);
- }
- }
- }
|