Spawn a prefab when wearing an armor

I was trying to spawn a prefab for the equipment as we did with weapons but I couldn’t figure out how to probably do it
any ideas?

Sorry if the code is messy
You will need to create a new empty class named Armor and put it on the prefab you want to spawn and all I did was reuse the weapon code and edit it a little
here is ONLY the changes not the full methods

//this goes in InventoryItem Script
        [SerializeField] Armor equippedarmor = null;
        const string EquipName = "Equip";

        public Armor Spawn(Transform EquipLocation)
        {
            Debug.Log("Spawn");
            DestroyOldWeapon(EquipLocation);

            Armor equipment = null;
            if (equippedarmor != null)
            {
                Transform handTransform = GetTransform(EquipLocation);
                equipment = Instantiate(equippedarmor, handTransform);
                equipment.gameObject.name = EquipName;
            }

            return equipment;
        }
        private void DestroyOldWeapon(Transform EquipLocation)
        {
            Transform oldEquip = EquipLocation.Find(EquipName);
            if (oldEquip == null)
            {
                oldEquip = EquipLocation.Find(EquipName);
            }
            if (oldEquip == null) return;

            oldEquip.name = "DESTROYING";
            Destroy(oldEquip.gameObject);
        }

        private Transform GetTransform(Transform EquipLocation)
        {
            Transform handTransform;
            handTransform = EquipLocation;
            return handTransform;
        }
//this goes in Fighter Script

        [SerializeField] Transform armorTransform = null;
        [SerializeField] InventoryItem defaultarmor = null;
        InventoryItem currentArmorConfig;
        LazyValue<Armor> currentArmor;
        private void Awake()
        {
            currentArmorConfig = defaultarmor;
            currentArmor = new LazyValue<Armor>(SetupDefaultArmor);
        }
        private Armor SetupDefaultArmor()
        {
            return AttachArmor(defaultarmor);
        }
        public void EquipArmor(InventoryItem armor)
        {
            currentArmorConfig = armor;
            currentArmor.value = AttachArmor(armor);

        }
        public void UpdateEquipment()
        {
            var armor = equipment.GetItemInSlot(EquipLocation.Body) as InventoryItem;
            if (armor == null)
            {
                EquipArmor(defaultarmor);
            }
            else
            {
                EquipArmor(armor);
            }
        }
        private Armor AttachArmor(InventoryItem armor)
        {
            Debug.Log("AttachArmor");

            return armor.Spawn(armorTransform);
        }

Screenshot_1
Screenshot_2

1 Like

Spawning armor is something that will vary greatly depending on the models you are choosing to employ. The most popular systems (Synty Modular Fantasy Hero and InfinityPBR Humans/Orcs/Elves) have multiple skinned meshes mapped to their skeleton, and you activate/deactivate meshes depending on which armor is worn.

I am currently running into this issue… I am using character Models from a couple different Synty packs… I picked up the modular characters, thinking getting them set would be relatively easy… Im finding that is not the case.

If you look at the Synty Fantasy Modular Hero, you’ll see that on the character and all of the “presets”, there are about 20 or so categories, each with up to 20 models under them. Each of these meshes is rigged to the skeleton. As a rule of thumb, you’re only going to want one of those models per category active at any one time. If you look at the character randomizer, you’ll get a starting point, as the randomizer essentially picks one from each category (well, depending on gender, some categories are always turned off). It’s not supermegaeasy. It’ll take some good quality time seeing how each one works and interacts with other components. For example, if you equip a Helmet No Hair item, it’s best to deactivate the character’s hair, but you have to remember to turn it back on if the helmet is removed.

This thread has some of what I did to make the synty pack works.

Hello, this is what I did for two of my projects, first the RPG course and the second part of the vid is something I’m doing in the RTS course, both some of the same coding. Followed some of the suggestions given in some of my other posts by the TA. A lot of other coding in places but mainly I’m turning all the parts off and then setactive the ones I want by ints and bools, set by the ScriptableObject of the armor, I also have the gender and skin color taken into account. Hope this helps or give some idea, and for the other thread.

1 Like

@RanMan That looks great! That is what I am trying to achieve! So far, I’ve managed to implement the equipment switching at run time, and I can test it out with some premade equipment layouts… BUT, I am running into an issue when saving… I get a serialization error if I try to save the current layout, but I am not sure quite sure why yet, so I am still working on that issue.
This is what Ive got so far, but no actual equippable Items yet, just skin changes, based on an integer…
Ill get there soon, lol.

@Brian_Trotter Thanks for the link! I will check it out!

My appearance class… which is based heavily on the Randomizer that came with the pack, but if it aint broke…

    public class ModularCharacterAppearance : MonoBehaviour
    {
        [SerializeField] bool presetCharacter;
        bool initalCharacterPreset;

        [SerializeField] EnabledItemsListHolder enabledObjectHolder;

        [SerializeField] Gender gender;

        [SerializeField, Range(0, 25)] int presetID = 0;
        int initialID;

        [Header("Material")]
        public Material mat;


        //Current parts lists.

        // list of enabed objects on character
        //[HideInInspector]
        public List<GameObject> enabledObjects = new List<GameObject>();       

        // list of the equipped items on the character(placeholder list to allow for modification);
        //[HideInInspector]
        public List<GameObject> equippedObjects = new List<GameObject>();


        // character object lists - used for referencing which part to enable or disable.

        // list of Male Gender Parts in Root.
        [HideInInspector]
        public CharacterObjectGroups male;

        // list of Female Gender Parts in Root.
        [HideInInspector]
        public CharacterObjectGroups female;

        // list of All Gender Parts in Root.
        [HideInInspector]
        public CharacterObjectListsAllGender allGender;


        //This list is for testing purposes... It holds intial state of the characters appearance, which is then used to switch back to the inital appearance, after switching prefabs.
        //It is currently planned to be temporarty but may come in handy later.
        private List<GameObject> initialObjects = new List<GameObject>();

        private void Awake()
        {
            initalCharacterPreset = presetCharacter;
            InitializePrefabAppearance();
            BuildInitialObjectsList();
            
            initialID = presetID;
        }

        private void Start()
        {
           
           
        }
        private void BuildInitialObjectsList()
        {
            foreach (GameObject go in enabledObjects)
            {
                initialObjects.Add(go);
            }
        }

        private void Update()
        {
            CheckCharacterSwap();
        }
        public List<GameObject> GetEnabledObjects()
        {
            return enabledObjects;
        }
        void CheckCharacterSwap()
        {
            if (initalCharacterPreset != presetCharacter)
            {
                initalCharacterPreset = presetCharacter;
                if (presetCharacter == false)
                {
                    enabledObjects.Clear();
                    equippedObjects.Clear();
                    foreach(GameObject go in initialObjects)
                    {
                        enabledObjects.Add(go);                        
                    }
                    BuildEquippedItemsList();
                    EquipItems();
                    
                }
                InitializePrefabAppearance();
            }
            if (presetCharacter)
            {
                if(initialID != presetID)
                {
                    initialID = presetID;
                    InitializePrefabAppearance();
                }
            }
            
            
            
        }
        private void InitializePrefabAppearance()
        {
            // rebuild all lists
            BuildPartsLists();

            // disable any enabled objects before clear and build equippedObjects list.
            if (enabledObjects.Count != 0)
            {
                BuildEquippedItemsList();
                DeactivateEnabledObjects();
            }


            // clear enabled objects list
            enabledObjects.Clear();
            // set custom character
            if (!presetCharacter)
            {
                EquipItems();
            }

            else
            {
                equippedObjects.Clear();
                // set default male character
                BuildPresetCharacterPartsList();

                BuildEquippedItemsList();

                enabledObjects.Clear();

                EquipItems();
            }
        }

        int CheckPreset(List<GameObject> list)
        {
            int newPresetID = presetID;

            if (newPresetID >= list.Count)
            {
                newPresetID = list.Count - 1;

                if (newPresetID < 0)
                { newPresetID = 0; }
                return newPresetID;
            }
            else { return presetID; }
        }

        private void DeactivateEnabledObjects()
        {
            foreach (GameObject g in enabledObjects)
            {

                g.SetActive(false);

            }
        }

        private void EquipItems()
        {
            foreach (GameObject g in equippedObjects)
            {
                ActivateItem(g);
            }
        }
        // enable game object and add it to the enabled objects list

        void ActivateItem(GameObject go)
        {
            // enable item
            go.SetActive(true);

            // add item to the enabled items list
            enabledObjects.Add(go);
        }

        /// ==========================================================================
        /// Builds Initial Parts List - Reference PsychoticLabs CharacterRandomizer.cs
        /// ==========================================================================

        #region Parts Lists
        private void BuildPresetCharacterPartsList()
        {
            if (gender == Gender.Male)
            {
                int headPresetID = CheckPreset(male.headAllElements);
                enabledObjects.Add(male.headAllElements[headPresetID]);

                int hairPresetID = CheckPreset(allGender.all_Hair);
                enabledObjects.Add(allGender.all_Hair[hairPresetID]);

                int eyebrowPresetID = CheckPreset(male.eyebrow);
                enabledObjects.Add(male.eyebrow[eyebrowPresetID]);

                int facialHairPresetID = CheckPreset(male.facialHair);
                enabledObjects.Add(male.facialHair[facialHairPresetID]);

                int torsoPresetID = CheckPreset(male.torso);
                enabledObjects.Add(male.torso[torsoPresetID]);

                int arm_Upper_Right_PresetID = CheckPreset(male.arm_Upper_Right);
                enabledObjects.Add(male.arm_Upper_Right[arm_Upper_Right_PresetID]);

                int arm_Upper_Left_PresetID = CheckPreset(male.arm_Upper_Left);
                enabledObjects.Add(male.arm_Upper_Left[arm_Upper_Left_PresetID]);

                int arm_Lower_Right_PresetID = CheckPreset(male.arm_Lower_Right);
                enabledObjects.Add(male.arm_Lower_Right[arm_Lower_Right_PresetID]);

                int arm_lower_Left_PresetID = CheckPreset(male.arm_Lower_Left);
                enabledObjects.Add(male.arm_Lower_Left[arm_lower_Left_PresetID]);

                int hand_Right_PresetID = CheckPreset(male.hand_Right);
                enabledObjects.Add(male.hand_Right[hand_Right_PresetID]);

                int hand_Left_PresetID = CheckPreset(male.hand_Left);
                enabledObjects.Add(male.hand_Left[hand_Left_PresetID]);

                int hip_PresetID = CheckPreset(male.hips);
                enabledObjects.Add(male.hips[hip_PresetID]);

                int leg_Right_PresetID = CheckPreset(male.leg_Right);
                enabledObjects.Add(male.leg_Right[leg_Right_PresetID]);

                int leg_Left_PresetID = CheckPreset(male.leg_Left);
                enabledObjects.Add(male.leg_Left[leg_Left_PresetID]);

            }
            else
            {
                int headPresetID = CheckPreset(female.headAllElements);
                enabledObjects.Add(female.headAllElements[headPresetID]);

                int hairPresetID = CheckPreset(allGender.all_Hair);
                enabledObjects.Add(allGender.all_Hair[hairPresetID]);

                int eyebrowPresetID = CheckPreset(female.eyebrow);
                enabledObjects.Add(female.eyebrow[eyebrowPresetID]);

                int torsoPresetID = CheckPreset(female.torso);
                enabledObjects.Add(female.torso[torsoPresetID]);

                int arm_Upper_Right_PresetID = CheckPreset(female.arm_Upper_Right);
                enabledObjects.Add(female.arm_Upper_Right[arm_Upper_Right_PresetID]);

                int arm_Upper_Left_PresetID = CheckPreset(female.arm_Upper_Left);
                enabledObjects.Add(female.arm_Upper_Left[arm_Upper_Left_PresetID]);

                int arm_Lower_Right_PresetID = CheckPreset(female.arm_Lower_Right);
                enabledObjects.Add(female.arm_Lower_Right[arm_Lower_Right_PresetID]);

                int arm_lower_Left_PresetID = CheckPreset(female.arm_Lower_Left);
                enabledObjects.Add(female.arm_Lower_Left[arm_lower_Left_PresetID]);

                int hand_Right_PresetID = CheckPreset(female.hand_Right);
                enabledObjects.Add(female.hand_Right[hand_Right_PresetID]);

                int hand_Left_PresetID = CheckPreset(female.hand_Left);
                enabledObjects.Add(female.hand_Left[hand_Left_PresetID]);

                int hip_PresetID = CheckPreset(female.hips);
                enabledObjects.Add(female.hips[hip_PresetID]);

                int leg_Right_PresetID = CheckPreset(female.leg_Right);
                enabledObjects.Add(female.leg_Right[leg_Right_PresetID]);

                int leg_Left_PresetID = CheckPreset(female.leg_Left);
                enabledObjects.Add(female.leg_Left[leg_Left_PresetID]);
            }
        }

        private void BuildEquippedItemsList()
        {
            foreach (GameObject g in enabledObjects)
            {
                equippedObjects.Add(g);
            }
        }

        // build all item lists for use with modular character
        private void BuildPartsLists()
        {
            //build out male lists
            BuildPartsList(male.headAllElements, "Male_Head_All_Elements");
            BuildPartsList(male.headNoElements, "Male_Head_No_Elements");
            BuildPartsList(male.eyebrow, "Male_01_Eyebrows");
            BuildPartsList(male.facialHair, "Male_02_FacialHair");
            BuildPartsList(male.torso, "Male_03_Torso");
            BuildPartsList(male.arm_Upper_Right, "Male_04_Arm_Upper_Right");
            BuildPartsList(male.arm_Upper_Left, "Male_05_Arm_Upper_Left");
            BuildPartsList(male.arm_Lower_Right, "Male_06_Arm_Lower_Right");
            BuildPartsList(male.arm_Lower_Left, "Male_07_Arm_Lower_Left");
            BuildPartsList(male.hand_Right, "Male_08_Hand_Right");
            BuildPartsList(male.hand_Left, "Male_09_Hand_Left");
            BuildPartsList(male.hips, "Male_10_Hips");
            BuildPartsList(male.leg_Right, "Male_11_Leg_Right");
            BuildPartsList(male.leg_Left, "Male_12_Leg_Left");

            //build out female lists
            BuildPartsList(female.headAllElements, "Female_Head_All_Elements");
            BuildPartsList(female.headNoElements, "Female_Head_No_Elements");
            BuildPartsList(female.eyebrow, "Female_01_Eyebrows");
            BuildPartsList(female.facialHair, "Female_02_FacialHair");
            BuildPartsList(female.torso, "Female_03_Torso");
            BuildPartsList(female.arm_Upper_Right, "Female_04_Arm_Upper_Right");
            BuildPartsList(female.arm_Upper_Left, "Female_05_Arm_Upper_Left");
            BuildPartsList(female.arm_Lower_Right, "Female_06_Arm_Lower_Right");
            BuildPartsList(female.arm_Lower_Left, "Female_07_Arm_Lower_Left");
            BuildPartsList(female.hand_Right, "Female_08_Hand_Right");
            BuildPartsList(female.hand_Left, "Female_09_Hand_Left");
            BuildPartsList(female.hips, "Female_10_Hips");
            BuildPartsList(female.leg_Right, "Female_11_Leg_Right");
            BuildPartsList(female.leg_Left, "Female_12_Leg_Left");

            // build out all gender lists
            BuildPartsList(allGender.all_Hair, "All_01_Hair");
            BuildPartsList(allGender.all_Head_Attachment, "All_02_Head_Attachment");
            BuildPartsList(allGender.headCoverings_Base_Hair, "HeadCoverings_Base_Hair");
            BuildPartsList(allGender.headCoverings_No_FacialHair, "HeadCoverings_No_FacialHair");
            BuildPartsList(allGender.headCoverings_No_Hair, "HeadCoverings_No_Hair");
            BuildPartsList(allGender.chest_Attachment, "All_03_Chest_Attachment");
            BuildPartsList(allGender.back_Attachment, "All_04_Back_Attachment");
            BuildPartsList(allGender.shoulder_Attachment_Right, "All_05_Shoulder_Attachment_Right");
            BuildPartsList(allGender.shoulder_Attachment_Left, "All_06_Shoulder_Attachment_Left");
            BuildPartsList(allGender.elbow_Attachment_Right, "All_07_Elbow_Attachment_Right");
            BuildPartsList(allGender.elbow_Attachment_Left, "All_08_Elbow_Attachment_Left");
            BuildPartsList(allGender.hips_Attachment, "All_09_Hips_Attachment");
            BuildPartsList(allGender.knee_Attachement_Right, "All_10_Knee_Attachement_Right");
            BuildPartsList(allGender.knee_Attachement_Left, "All_11_Knee_Attachement_Left");
            BuildPartsList(allGender.elf_Ear, "Elf_Ear");
        }

        // called from the BuildPartsLists method
        void BuildPartsList(List<GameObject> targetList, string characterPart)
        {
            Transform[] rootTransform = gameObject.GetComponentsInChildren<Transform>();

            // declare target root transform
            Transform targetRoot = null;

            // find character parts parent object in the scene
            foreach (Transform t in rootTransform)
            {
                if (t.gameObject.name == characterPart)
                {
                    targetRoot = t;
                    break;
                }
            }

            // clears targeted list of all objects
            targetList.Clear();

            // cycle through all child objects of the parent object
            for (int i = 0; i < targetRoot.childCount; i++)
            {
                // get child gameobject index i
                GameObject go = targetRoot.GetChild(i).gameObject;

                // disable child object
                go.SetActive(false);

                // add object to the targeted object list
                targetList.Add(go);

                // collect the material for the random character, only if null in the inspector;
                if (!mat)
                {
                    if (go.GetComponent<SkinnedMeshRenderer>())
                        mat = go.GetComponent<SkinnedMeshRenderer>().material;
                    print(go + " - " + mat.name);
                }
            }
        }

       
    }

    // classe for keeping the lists organized, allows for simple switching from male/female objects
    [System.Serializable]
    public class CharacterObjectGroups
    {
        public List<GameObject> headAllElements;
        public List<GameObject> headNoElements;
        public List<GameObject> eyebrow;
        public List<GameObject> facialHair;
        public List<GameObject> torso;
        public List<GameObject> arm_Upper_Right;
        public List<GameObject> arm_Upper_Left;
        public List<GameObject> arm_Lower_Right;
        public List<GameObject> arm_Lower_Left;
        public List<GameObject> hand_Right;
        public List<GameObject> hand_Left;
        public List<GameObject> hips;
        public List<GameObject> leg_Right;
        public List<GameObject> leg_Left;
    }

    // classe for keeping the lists organized, allows for organization of the all gender items
    [System.Serializable]
    public class CharacterObjectListsAllGender
    {
        public List<GameObject> headCoverings_Base_Hair;
        public List<GameObject> headCoverings_No_FacialHair;
        public List<GameObject> headCoverings_No_Hair;
        public List<GameObject> all_Hair;
        public List<GameObject> all_Head_Attachment;
        public List<GameObject> chest_Attachment;
        public List<GameObject> back_Attachment;
        public List<GameObject> shoulder_Attachment_Right;
        public List<GameObject> shoulder_Attachment_Left;
        public List<GameObject> elbow_Attachment_Right;
        public List<GameObject> elbow_Attachment_Left;
        public List<GameObject> hips_Attachment;
        public List<GameObject> knee_Attachement_Right;
        public List<GameObject> knee_Attachement_Left;
        public List<GameObject> all_12_Extra;
        public List<GameObject> elf_Ear;
    }
    #endregion
}

I’m writing this class to save the currently equipped items… and initializes and sets up correctly, but if I try to save, I’m getting a serialization error. I’ve tried a couple different methods… but so far nothing has worked. from creating just trying to restore the list from (List)state; but that didnt work, so I tried a dictionary<int, GameObject>, of the game objects in the list, and then restore the list from that dictionary, but no luck…

    public class EnabledItemsListHolder : MonoBehaviour, ISaveable
    {
        public List<GameObject> enabledObjects = new List<GameObject>();
        ModularCharacterAppearance appearance;
        bool firstTime = true;
        void Start()
        {
            if (firstTime)
            {
                appearance = FindObjectOfType<ModularCharacterAppearance>();
                enabledObjects = appearance.GetEnabledObjects();
                firstTime = false;
            }
            else
            {
                appearance = FindObjectOfType<ModularCharacterAppearance>();
            }
        }
        public object CaptureState()
        {
            Dictionary<int, GameObject> data =  new Dictionary<int, GameObject>();
            {
                for (int i = 0; i < enabledObjects.Count - 1; i++)
                {
                    data[i] = enabledObjects[i];
                }
            }
            return data;
        }

        public void RestoreState(object state)
        {
            Dictionary <int, GameObject> data = (Dictionary<int, GameObject>)state;
            enabledObjects.Clear();
            foreach(KeyValuePair<int, GameObject> pair in data)
            {
                enabledObjects.Add(pair.Value);
            }

        }

        // Update is called once per frame
        void Update()
        {

        }
    }

Nicely done!

@Brian_Trotter Any ideas why I would be getting a Serialization Error with this capture?

 public object CaptureState()
        {
            Dictionary<string, GameObject> data = new Dictionary<string, GameObject>();
            for (int i = 0; i < equippedObjects.Count; i++)
            {
                
                data[$"{i}"] = equippedObjects[i];
                print($"{data[$"{i}"].name}");
            }

            return data;
        }

if I return, something other than Data, ie: a string, then I can save and restore, that string, and it works as intended… But, when I try to capture the dictionary (as I have previously) I get a the following

SerializationException: Type 'UnityEngine.GameObject' in Assembly 'UnityEngine.CoreModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' is not marked as serializable.
System.Runtime.Serialization.FormatterServices.InternalGetSerializableMembers (System.RuntimeType type) (at <695d1cc93cca45069c528c15c9fdd749>:0)
System.Runtime.Serialization.FormatterServices+<>c__DisplayClass9_0.<GetSerializableMembers>b__0 (System.Runtime.Serialization.MemberHolder _) (at <695d1cc93cca45069c528c15c9fdd749>:0)
System.Collections.Concurrent.ConcurrentDictionary`2[TKey,TValue].GetOrAdd (TKey key, System.Func`2[T,TResult] valueFactory) (at <695d1cc93cca45069c528c15c9fdd749>:0)
System.Runtime.Serialization.FormatterServices.GetSerializableMembers (System.Type type, System.Runtime.Serialization.StreamingContext context) (at <695d1cc93cca45069c528c15c9fdd749>:0)
System.Runtime.Serialization.Formatters.Binary.WriteObjectInfo.InitMemberInfo () (at <695d1cc93cca45069c528c15c9fdd749>:0)
System.Runtime.Serialization.Formatters.Binary.WriteObjectInfo.InitSerialize (System.Object obj, System.Runtime.Serialization.ISurrogateSelector surrogateSelector, System.Runtime.Serialization.StreamingContext context, System.Runtime.Serialization.Formatters.Binary.SerObjectInfoInit serObjectInfoInit, System.Runtime.Serialization.IFormatterConverter converter, System.Runtime.Serialization.Formatters.Binary.ObjectWriter objectWriter, System.Runtime.Serialization.SerializationBinder binder) (at <695d1cc93cca45069c528c15c9fdd749>:0)
System.Runtime.Serialization.Formatters.Binary.WriteObjectInfo.Serialize (System.Object obj, System.Runtime.Serialization.ISurrogateSelector surrogateSelector, System.Runtime.Serialization.StreamingContext context, System.Runtime.Serialization.Formatters.Binary.SerObjectInfoInit serObjectInfoInit, System.Runtime.Serialization.IFormatterConverter converter, System.Runtime.Serialization.Formatters.Binary.ObjectWriter objectWriter, System.Runtime.Serialization.SerializationBinder binder) (at <695d1cc93cca45069c528c15c9fdd749>:0)
System.Runtime.Serialization.Formatters.Binary.ObjectWriter.Write (System.Runtime.Serialization.Formatters.Binary.WriteObjectInfo objectInfo, System.Runtime.Serialization.Formatters.Binary.NameInfo memberNameInfo, System.Runtime.Serialization.Formatters.Binary.NameInfo typeNameInfo) (at <695d1cc93cca45069c528c15c9fdd749>:0)
System.Runtime.Serialization.Formatters.Binary.ObjectWriter.WriteArrayMember (System.Runtime.Serialization.Formatters.Binary.WriteObjectInfo objectInfo, System.Runtime.Serialization.Formatters.Binary.NameInfo arrayElemTypeNameInfo, System.Object data) (at <695d1cc93cca45069c528c15c9fdd749>:0)
System.Runtime.Serialization.Formatters.Binary.ObjectWriter.WriteArray (System.Runtime.Serialization.Formatters.Binary.WriteObjectInfo objectInfo, System.Runtime.Serialization.Formatters.Binary.NameInfo memberNameInfo, System.Runtime.Serialization.Formatters.Binary.WriteObjectInfo memberObjectInfo) (at <695d1cc93cca45069c528c15c9fdd749>:0)
System.Runtime.Serialization.Formatters.Binary.ObjectWriter.Write (System.Runtime.Serialization.Formatters.Binary.WriteObjectInfo objectInfo, System.Runtime.Serialization.Formatters.Binary.NameInfo memberNameInfo, System.Runtime.Serialization.Formatters.Binary.NameInfo typeNameInfo) (at <695d1cc93cca45069c528c15c9fdd749>:0)
System.Runtime.Serialization.Formatters.Binary.ObjectWriter.Serialize (System.Object graph, System.Runtime.Remoting.Messaging.Header[] inHeaders, System.Runtime.Serialization.Formatters.Binary.__BinaryWriter serWriter, System.Boolean fCheck) (at <695d1cc93cca45069c528c15c9fdd749>:0)
System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Serialize (System.IO.Stream serializationStream, System.Object graph, System.Runtime.Remoting.Messaging.Header[] headers, System.Boolean fCheck) (at <695d1cc93cca45069c528c15c9fdd749>:0)
System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Serialize (System.IO.Stream serializationStream, System.Object graph, System.Runtime.Remoting.Messaging.Header[] headers) (at <695d1cc93cca45069c528c15c9fdd749>:0)
System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Serialize (System.IO.Stream serializationStream, System.Object graph) (at <695d1cc93cca45069c528c15c9fdd749>:0)
GameDevTV.Saving.SavingSystem.SaveFile (System.String saveFile, System.Object state) (at Assets/---Game Files----/Scripts/Saving/SavingSystem.cs:104)
GameDevTV.Saving.SavingSystem.Save (System.String saveFile) (at Assets/---Game Files----/Scripts/Saving/SavingSystem.cs:44)
RPG.SceneManagement.SavingWrapper.Save (System.String saveFile) (at Assets/---Game Files----/Scripts/Saving/SavingWrapper.cs:91)
RPG.SceneManagement.ScenePortal+<LoadScene>d__10.MoveNext () (at Assets/---Game Files----/Scripts/Core/ScenePortal.cs:99)
UnityEngine.SetupCoroutine.InvokeMoveNext (System.Collections.IEnumerator enumerator, System.IntPtr returnValueAddress) (at <07c89f7520694139991332d3cf930d48>:0)
UnityEngine.MonoBehaviour:StartCoroutine(IEnumerator)
RPG.SceneManagement.ScenePortal:OnTriggerEnter(Collider) (at Assets/---Game Files----/Scripts/Core/ScenePortal.cs:37)

If I investigate the error, it takes me to the Saving System, and I dont know how to track down what the issue may be. I have cleared out my save files, as was previously the fix, but it does not capture.

Edit: the reason I am using the string key in the dicionary is because I was getting the error with an int, and I referenced previous uses of a dictionary in the capture state that used strings, and capture fine…

Edit2: I also tried just returning the enabledObjects list, and still get the same error… ie:

 public object CaptureState()
        {
           return enabledObjects; //returns a List<GameObject> "enabledObjects".
        }

Also, it should be noted, I am casting to the correct object type in restore, but it doesn’t make it that far…

The saving system can’t handle GameObjects directly. In fact, there are several thing the saving system can’t handle, like Vector3, MonoBehavior, ScriptableObject, etc. This is why we save a string for InventoryItems, and then look up the items by string reference.

Your approach is a bit different than mine was, as I simply polled the Equipment and got the information needed from the EquipableItem. Generally speaking, though, if you save the name of the GameObject, you can search the transform for that name and activate it or deactivate it.

Ahhh! Thank you. I thought since I was casting it back to the correct type it would work. I’ll think of another solution. Thanks again!

Hum, for my equipment the save is the same as the course, the way I have the prefab of the model turn on and off is based on info from saved equipment item. So when the restore state is called the equipment.equipmentUpdated the model parts are set again. Hope this is what you are looking for as far as having the same model show up with the saved equipment.

private void Awake()
        {
            this.gender = characterHolder.GetGender();

            currentHipArmorConfig = defaultHipArmor;
            SetupDefaultAmor();
            if (equipment)
            {
                equipment.equipmentUpdated += UpdateArmor;
            }
        }
        void Update()
        {
            IsHAmorSameEelement();
        }
        private void IsHAmorSameEelement()
        {
            if (element.GetElement() == currentHipArmorConfig.GetElementType())
            {
                currentHipArmorConfig.UseElementBonus(true);
            }
            else
            {
                currentHipArmorConfig.UseElementBonus(false);
            }
        }

        #region Equipping HipArmor
        private void SetupDefaultAmor()
        {
            if (gender == Gender.Male)
            {
                MaleAttachHipArmor(defaultHipArmor);
            }
            if (gender == Gender.Female)
            {
                FemaleAttachHipArmor(defaultHipArmor);
            }
        }
        private void UpdateArmor()
        {
            if (maleHip == null && femaleHip == null) return;

            var armor = equipment.GetItemInSlot(EquipLocation.Legs) as HipArmorConfig;
            if (armor == null)
            {
                EquipHipArmor(defaultHipArmor);
            }
            else
            {
                EquipHipArmor(armor);
            }
        }
        private void EquipHipArmor(HipArmorConfig armor)
        {
            currentHipArmorConfig = armor;
            if (gender == Gender.Male)
            {
                MaleAttachHipArmor(armor);
            }
            if (gender == Gender.Female)
            {
                FemaleAttachHipArmor(armor);
            }
        }
        #endregion

        #region HipArmorSets
        //Male
        private void MaleAttachHipArmor(HipArmorConfig armor)
        {
            maleHip.SetGearFull(armor.GetGearNumber(), armor.GetElementType(), characterHolder.GetSkinNumber());  
            maleRight.SetGearFull(armor.GetRightNumber(), armor.GetElementType(), characterHolder.GetSkinNumber());
            maleLeft.SetGearFull(armor.GetLeftNumber(), armor.GetElementType(), characterHolder.GetSkinNumber());

            AddOnGearSet(armor, maleHip.GetMaterial());     
        }
        //Female
        private void FemaleAttachHipArmor(HipArmorConfig armor)
        {
            femaleHip.SetGearFull(armor.GetGearNumber(), armor.GetElementType(), characterHolder.GetSkinNumber());
            femaleRight.SetGearFull(armor.GetRightNumber(), armor.GetElementType(), characterHolder.GetSkinNumber());
            femaleLeft.SetGearFull(armor.GetLeftNumber(), armor.GetElementType(), characterHolder.GetSkinNumber());

            AddOnGearSet(armor, femaleHip.GetMaterial()); 
        }

        private void AddOnGearSet(HipArmorConfig armor, Material material)
        {
            minorGearSet.ClearGear();
            minorGearSet.SetAddOnGear(armor, material);
        }
        #endregion
    }

Don’t mind the floating man, or change in lighting lol, haven’t tried to fix that yet, using rigid body movement.

So what I did for both the character itself and the armor was to make arrays out of all of the elements on the Synty Modular character. Essentially, they’re the same arrays generated in the CharacterRandomizer.cs that comes with the asset pack.

This allowed me to refer just to the part category and an array element…
For the base character with no armor, I have ints to indicate each part… i.e
int head = 1;
This means for the base character, you just need to save the ints… I made a struct that was decoded, but you could also make a Dictionary keyed to the categories.

The SyntyEquipableItem I created has three lists…

  1. ItemsToRemove, this is a list of strings of category names that should be removed when equipping this item. For example, for some helmets, it’s best if you remove the hair or the facial hair. The CharacterGenerator will deactivate any elements in that list.
  2. Items To Activate, each element being the category and the index into the category of the item. My CharacterGenerator will automagically deactivate anything else in that category.
  3. Color changes, any color categories that need to have their color overriden. That used to be an int into an index of pre-defined colors, but in my currrent project, I just use a Color.

Since these things are in the SyntyEquipableItem, there’s no extra steps needed to save them, the Equipment automatically saves everything in every slot.

1 Like

I’ve finally done it! After a couple failed attempts, I have finally accomplished my goal! I am really please with the system I’ve come up with, it allows for total customization of what material each component uses(for different colored armor sets), which items spawn/get hidden/ or reset to a default value on equip! I did end up having to redo my initial appearance manager, but it was worth the experimentation. I learned a lot! So far I have only set up an “Iron Armor” set, and “Leather Armor” set, but the possibilities are exciting!
Also, I have not implemented Shields yet, but that my next goal.

1 Like

Well done!

The good news is that shields are as easy as weapons to set up.

yeah, getting Shields set up wasn’t too bad. The issue I’m running into at the moment is with weapons that should be 2 handed such as the bow, or a two handed sword I have set up, the weapon/shield equipped in the other hand doesn’t go away, so he holds both a bow and a sword, or a shield while wielding a huge sword with two hands, so it looks pretty rediculous at the moment.

For that, you need to make checks during the equip phase… the simplest check would be in the EquipmentSlotUI’s MaxAcceptable… something like

if(!(item is EquipableItem equipableItem) return 0;
if(equipableItem.GetEquipLocation()!=slot) return 0;
if(slot==Slot.Shield)
{
      EquipableItem weapon = equipment.GetItemInSlot(Slot.Weapon);
      if(weapon && (weapon.IsTwoHanded || weapon.IsLeftHanded)) return 0;
      
} else if (slot == Slot.Weapon && (equipableItem.IsLeftHanded || equipableItem.IsTwoHanded))
{
     EquipableItem shield = equipment.GetItemInSlot(Slot.Shield);
     return shield==null? 0:1;
}
return 1;

Please note that I wrote this function on my laptop in the basement where I’m doing a wood cutting project, and I have no access to the code base… Clearly, you’ll need to add an isTwoHanded to the WeaponConfig, and make both isTwoHanded and isLeftHanded exposed via a property

public bool IsLeftHanded =>isLeftHanded;
public bool IsTwoHanded =>isTwoHanded;

On top of that, I may have misspelled or misnamed a method call or two in all fo that. I’m fairly confident you’ll work right through any errors.

Privacy & Terms