Custom AttributeManager Saver Issues

Announcements, support questions, and discussion for Save System for Opsive Character Controllers.
Post Reply
clintond
Posts: 4
Joined: Tue Jan 07, 2025 4:50 am

Custom AttributeManager Saver Issues

Post by clintond »

Hi Tony

I've searched high and wide and cannot solve the following issue:

- Using UIS/UCC Savers.
- Have implemented some custom savers from the Saver class successfully.

However, having problems with the following:

1. Flashlight, pickup. Have attached the DestructibleSaver (On Destroy/Destroy).
2. On the Flashlight prefab the player uses, I have an Attribute named Battery, controlled via the UCC AttributeManager.
3. I'm trying to save/load that data.
4. I've created a custom Saver that is a stripped down version of your UCC Saver, as I see you can handle Attributes there (and the UCCSaver works fine for the many Attributes I have on the character). Script below.

The above is able to SAVE the data, no problem. However I cannot manage to get the data to load. I've tried many things including subscribing to events.

I also have other issues, which I'll mention as an FYI.

- Some times, the Flashlight prefab re-appears after load, other times it doesn't.
- I end up with NULL references to the custom Saver script on the Flashlight (I guess the instance of it dies during the LOAD state).

Your guidance on this is really appreciated.

Thanks, clinton

--

Code: Select all

using System;
using System.Collections.Generic;
using UnityEngine;
using PixelCrushers; 
using Opsive.UltimateCharacterController.Traits;

namespace desiderium
{
    [RequireComponent(typeof(AttributeManager))]
    public class AttributeSaver : Saver
    {
        [Serializable]
        public class Data
        {
            public List<float> attributeValues = new List<float>();
            public List<float> attributeMins = new List<float>();
            public List<float> attributeMaxes = new List<float>();
        }

        private Data m_Data = new Data();

        public override string RecordData()
        {
            var attributeManager = GetComponent<AttributeManager>();
            if (attributeManager == null)
            {
                return string.Empty;
            }

            m_Data.attributeValues.Clear();
            m_Data.attributeMins.Clear();
            m_Data.attributeMaxes.Clear();
            for (int i = 0; i < attributeManager.Attributes.Length; i++)
            {
                var attr = attributeManager.Attributes[i];
                m_Data.attributeValues.Add(attr.Value);
                m_Data.attributeMins.Add(attr.MinValue);
                m_Data.attributeMaxes.Add(attr.MaxValue);
            }

            var serialized = SaveSystem.Serialize(m_Data);
            return serialized;
        }

        public override void ApplyData(string dataString)
        {
            if (string.IsNullOrEmpty(dataString)) return;

            var newData = SaveSystem.Deserialize<Data>(dataString);
            if (newData == null)
            {
                return;
            }

            var attributeManager = GetComponent<AttributeManager>();
            if (attributeManager == null)
            {
                return;
            }

            var attrCount = attributeManager.Attributes.Length;
            var dataCount = newData.attributeValues.Count;
            var count = Mathf.Min(attrCount, dataCount);

            bool hasMinData = (newData.attributeMins.Count == dataCount);
            bool hasMaxData = (newData.attributeMaxes.Count == dataCount);

            for (int i = 0; i < count; i++)
            {
                if (hasMinData) attributeManager.Attributes[i].MinValue = newData.attributeMins[i];
                if (hasMaxData) attributeManager.Attributes[i].MaxValue = newData.attributeMaxes[i];
                attributeManager.Attributes[i].Value = newData.attributeValues[i];
            }
        }
        public override void Start()
        {
            SaveSystem.loadEnded += OnLoadEnded;
        }

        public override void OnDisable()
        {
            SaveSystem.loadEnded -= OnLoadEnded;
        }

        private void OnLoadEnded()
        {
            SaveSystem.ApplySavedGameData();
        }
    }

}
User avatar
Tony Li
Posts: 22465
Joined: Thu Jul 18, 2013 1:27 pm

Re: Custom AttributeManager Saver Issues

Post by Tony Li »

Hi,

I recommend adding Debug.Log lines before exiting out of each of the two null checks in ApplyData. It may be erroring out unexpectedly.

However, before you do that, are you using UIS for items? If so, can you take a different approach? If you treat the flashlight like a UIS item and set up the save system integration with UIS, then UIS's save module will take care of it.
clintond
Posts: 4
Joined: Tue Jan 07, 2025 4:50 am

Re: Custom AttributeManager Saver Issues

Post by clintond »

Hi Tony

Thanks for getting back to me.

Yes, I’m using UIS for the inventory management and have configured the SaveSystem to work with it, which it does. The items in the inventory persist, as does the Equipped status of the Flashlight. However the Battery status does not persist.

I wonder if adding a UCCSaver to the flashlight prefab could work - with only the Attributes option selected? I’ll try that, unless there’s something else specific you’re thinking of.

Thanks again.
User avatar
Tony Li
Posts: 22465
Joined: Thu Jul 18, 2013 1:27 pm

Re: Custom AttributeManager Saver Issues

Post by Tony Li »

Hi,

The Pixel Crushers Save System hands off the work of saving UIS data to UIS's InventorySystemManager. The UISSaver component basically acts like a middleman between UIS's InventorySystemManager and the rest of the Save System. The InventorySystemManager should handle saving of items' attributes. If you're also using a custom saver to restore those attributes, they could be stepping on each others' toes. Can you get UIS to save the attributes? You may need to hit up the dev, Santiago (Sangemdoko on Opsive's Discord server), if you have questions about saving the attributes in UIS.
clintond
Posts: 4
Joined: Tue Jan 07, 2025 4:50 am

Re: Custom AttributeManager Saver Issues

Post by clintond »

Ah, makes sense now.

UIS isn’t saving the attribute, which is why I’m on this journey :)

I’ll chat with Santiago.

Thanks Tony!
User avatar
Tony Li
Posts: 22465
Joined: Thu Jul 18, 2013 1:27 pm

Re: Custom AttributeManager Saver Issues

Post by Tony Li »

Glad to help! If it ends up being something Save System-related, just let me know and I'll jump back into the conversation.
clintond
Posts: 4
Joined: Tue Jan 07, 2025 4:50 am

Re: Custom AttributeManager Saver Issues

Post by clintond »

Hi Tony

Just to close off this thread, and for anyone who might find it useful in the future.

Yes, it was something that needed to be solved on the UIS side.

After speaking with Santiago, he directed me to the ItemBinding component that can be used in these instances.

It still required a bit of custom code to bind between the UCC attribute and the UIS one, yet it was doable without too much effort (just a lot of understanding!),

Here's the UIS documentation for future reference:

https://opsive.com/support/documentatio ... m-binding/

Thanks again.
User avatar
Tony Li
Posts: 22465
Joined: Thu Jul 18, 2013 1:27 pm

Re: Custom AttributeManager Saver Issues

Post by Tony Li »

Thanks for posting the update here. Good to know!
Post Reply