- Home /
The question is answered, right answer was accepted
Unity applyModifiedproperties doesnt update my properties
Hello, I am trying to serialize a dictionary for easy editing. but my values dont update. and are reset to zero. my code has a general class_controller that my Player_Controller inherit from. and have a custom editor that inherit from here.
Class_Controller
public abstract class Class_Controller : MonoBehaviour, ISerializationCallbackReceiver
{
[SerializeField] protected bool debug;
#region attributes and derivative
[Header("Ability Scores")]
[SerializeField] int Strength;
[SerializeField] int Dexterity, Intelligence, Faith;
public int MaxHealth { get => 10 + Strength*5; }
public int MaxStamina { get => 200 + Dexterity * 100; }
public int MaxMana { get => 5 + Intelligence * 10; }
public int MaxFavors { get => Faith * 5; }
[Header("Stats")]
int health;
int stamina, mana, favors;
#endregion
#region Health System
public enum DamageType { Slashing, Blunt }
[Serializable]
public class serialized_Dict<v> : Dictionary<DamageType, v>, ISerializationCallbackReceiver
{
[SerializeField]
List<v> values = new List<v>(Enum.GetValues(typeof(DamageType)).Length);
public void OnAfterDeserialize()
{
Clear();
foreach (int i in Enum.GetValues(typeof(DamageType)))
Add((DamageType)i, values[i]);
}
public void OnBeforeSerialize()
{
values.Clear();
foreach (DamageType i in Enum.GetValues(typeof(DamageType)))
values.Add(this[i]);
}
}
[Serializable]
class resistance : serialized_Dict<float> { }
[Serializable]
class armor : serialized_Dict<int> { }
[Header("Armor")]
[SerializeField] [HideInInspector] resistance resistences;
[SerializeField] [HideInInspector] armor armors;
public int Health { get => health; }
void Die()
{
animator.enabled = false;
}
public void TakeDamage(Dictionary<DamageType, int> damages)
{
foreach (DamageType damage in damages.Keys)
{
int d = (int)(damages[damage] * (1 - resistences[damage])) - armors[damage];
health -= d < 0 ? 0 : d;
}
if (health <= 0) Die();
}
public void Heal(int value)
{
health += value;
if (health > MaxHealth) health = MaxHealth;
}
#endregion
#region Stamina System
int staminaRegen { get => Dexterity + 1; }
public int Stamina { get => stamina; }
private void FixedUpdate()
{
if (stamina < MaxStamina) stamina += (int)(staminaRegen * Time.fixedDeltaTime);
UIManager();
}
public bool DrainStamina(int s)
{
if (stamina < s) return false;
stamina -= s; return true;
}
#endregion
#region Animation
float maxSpeed { get => Dexterity * 2 + Strength; }
protected abstract Vector3 MovementDirection();
protected Animator animator;
const float walkSpeed = 1;
protected void OnAnimatorMove()
{
transform.Translate(MovementDirection().normalized * walkSpeed * Time.deltaTime);
animator?.SetFloat("Velocity", MovementDirection().magnitude);
}
#endregion
#region UI
List<int> armorStats; List<float> resistanceStats;
public void OnBeforeSerialize()
{
armorStats.Clear(); resistanceStats.Clear();
foreach (DamageType i in Enum.GetValues(typeof(DamageType)))
{
armorStats.Add(armors[i]); resistanceStats.Add(resistences[i]);
}
}
public void OnAfterDeserialize()
{
armors.Clear(); resistences.Clear();
foreach (int i in Enum.GetValues(typeof(DamageType)))
{
try { armors.Add((DamageType)i, armorStats[i]); resistences.Add((DamageType)i, resistanceStats[i]); }
catch { armors.Add((DamageType)i, 0); resistences.Add((DamageType)i, 0f); }
}
}
#endregion
public Class_Controller()
{
armors = new armor(); resistences = new resistance();
armorStats = new List<int>(); resistanceStats = new List<float>();
foreach (DamageType item in Enum.GetValues(typeof(DamageType)))
{
armors.Add(item, 0); resistences.Add(item, 0f);
}
}
protected abstract void UIManager();
protected void Awake()
{
health = MaxHealth;
animator = GetComponent<Animator>();
if (transform.GetComponentsInChildren<Rigidbody>().Length == 0)
this.gameObject.AddComponent(typeof(Rigidbody));
gameObject.layer = 8;
}
}
the custom editor of Class_Controller
[CustomEditor(typeof(Class_Controller))]
public class Visualizer : Editor
{
SerializedProperty armor, resistance;
private void Awake()
{
armor = serializedObject.FindProperty("armors").FindPropertyRelative("values");
resistance = serializedObject.FindProperty("resistences").FindPropertyRelative("values");
}
public override void OnInspectorGUI()
{
serializedObject.Update();
bool debug = serializedObject.FindProperty("debug").boolValue;
DrawDefaultInspector();
EditorGUILayout.Space();
EditorGUILayout.LabelField("Armor", EditorStyles.boldLabel);
foreach (int i in Enum.GetValues(typeof(Class_Controller.DamageType)))
{
if (debug) Debug.Log($"{Enum.GetName(typeof(Class_Controller.DamageType), i)} Before: A: {armor.GetArrayElementAtIndex(i).intValue} R: {resistance.GetArrayElementAtIndex(i).floatValue}");
armor.GetArrayElementAtIndex(i).intValue = EditorGUILayout.IntField(Enum.GetName(typeof(Class_Controller.DamageType), i), armor.GetArrayElementAtIndex(i).intValue);
resistance.GetArrayElementAtIndex(i).floatValue = EditorGUILayout.Slider(resistance.GetArrayElementAtIndex(i).floatValue, 0, 1);
if (debug) Debug.Log($"{Enum.GetName(typeof(Class_Controller.DamageType), i)} After: A: {armor.GetArrayElementAtIndex(i).intValue} R: {resistance.GetArrayElementAtIndex(i).floatValue}");
}
if (debug) Debug.Log($"Modeified {serializedObject.hasModifiedProperties}");
serializedObject.ApplyModifiedProperties();
}
}
found that although hasModifiedProperties return true, the changes dont apply. and the documentation on this subject is empty.
Answer by warmagedon-007 · Jan 19, 2020 at 07:59 AM
After many tries I found that the problem is in the UI region with the desiralization reseting my armor and resistance to zero, so after the interface and region removal it works
Follow this Question
Related Questions
Saving data through FileStream DataInfo? Think i'm misunderstanding something. 1 Answer
Storing data about an asset only in the editor 2 Answers
Custom Editor Button Style like the one in the Hierarchy 0 Answers
OnBeforeSerialize constantly called in Editor Mode 1 Answer
UnityEvent Serialization Problem 1 Answer