logo SERENITY
Game Systems Foundation
Search Results for

    Show / Hide Table of Contents

    Class AchievementConditionNodeWriter

    Every write the condition tree drawer makes to an authored tree: replacing a node with another type, adding, removing and reordering a composite's children, and clearing the tree.

    Inheritance
    object
    AchievementConditionNodeWriter
    Inherited Members
    object.ToString()
    object.Equals(object)
    object.Equals(object, object)
    object.ReferenceEquals(object, object)
    object.GetHashCode()
    object.GetType()
    object.MemberwiseClone()
    Namespace: Serenity.Achievements.Infrastructure.Editor
    Assembly: Serenity.UnityAchievements.Infrastructure.Editor.dll
    Syntax
    public static class AchievementConditionNodeWriter
    Remarks

    Separate from AchievementConditionNodeGui so the drawing stays reading-only and the writes stay in one place, because they all share three rules that are easy to get wrong.

    First, everything goes through UnityEditor.SerializedProperty rather than through the managed object the property holds. Assigning a node's fields directly would edit the loaded instance behind the serialization system's back: no undo entry, no prefab override, and no repaint for the other inspector looking at the same asset.

    Second, a choice made in an AdvancedDropdown arrives AFTER the GUI pass that opened it has already applied its changes, so the property captured during that pass is stale and writing through it silently does nothing. Every method that a dropdown calls back into takes the owning UnityEditor.SerializedObject and a property path and re-finds the property — the same deferral SerenityTypeSearchPicker.WriteStringDeferred makes for string fields.

    Third, each write applies its own serialized changes, so a host watching only its own ApplyModifiedProperties never sees them. Every successful write tells the AchievementConditionEditContext, which is how an inspector's project-wide findings stop describing a tree the author already changed.

    Fields

    ChildrenField

    The serialized name of the child list every composite carries.

    Declaration
    public const string ChildrenField = "conditions"
    Field Value
    Type Description
    string

    InnerField

    The serialized name of the single child every wrapper carries.

    Declaration
    public const string InnerField = "inner"
    Field Value
    Type Description
    string

    ReplaceDialogTitle

    Heading of the question asked before a replacement drops children.

    Declaration
    public const string ReplaceDialogTitle = "Replace condition"
    Field Value
    Type Description
    string

    ReplaceNodeUndoLabel

    Undo label for a node type change.

    Declaration
    public const string ReplaceNodeUndoLabel = "Change Condition Type"
    Field Value
    Type Description
    string

    Methods

    AppendChildDeferred(SerializedObject, string, Type, AchievementConditionEditContext)

    Appends a new child of the given type to a composite's list.

    Declaration
    public static void AppendChildDeferred(SerializedObject owner, string listPath, Type childType, AchievementConditionEditContext context)
    Parameters
    Type Name Description
    SerializedObject owner

    The serialized object the tree belongs to.

    string listPath

    Path of the composite's child list.

    Type childType

    The concrete condition type to append.

    AchievementConditionEditContext context

    What the drawer was given to write with.

    ChildLossQuestion(AchievementCondition, AchievementCondition, int)

    What the author is asked before a replacement drops children.

    Declaration
    public static string ChildLossQuestion(AchievementCondition previous, AchievementCondition replacement, int lostChildCount)
    Parameters
    Type Name Description
    AchievementCondition previous

    The node being replaced.

    AchievementCondition replacement

    The node replacing it.

    int lostChildCount

    How many children the replacement cannot hold.

    Returns
    Type Description
    string

    The question.

    ChildrenToCarryOver(AchievementCondition, AchievementCondition)

    The children a replacement node can take over from the node it replaces.

    Declaration
    public static List<AchievementCondition> ChildrenToCarryOver(AchievementCondition previous, AchievementCondition replacement)
    Parameters
    Type Name Description
    AchievementCondition previous

    The node being replaced. May be null.

    AchievementCondition replacement

    The node replacing it.

    Returns
    Type Description
    List<AchievementCondition>

    The children to carry over, in order.

    Remarks

    A composite takes everything, so swapping between All Of, Any Of and In Order keeps the whole authored list, and promoting a wrapper to a composite keeps its one child. A wrapper takes over only from another wrapper: taking the first child of a composite would throw the rest away without saying so, and an author who meant that can remove them. A leaf takes nothing, because it has nowhere to put them.

    ClearDeferred(SerializedObject, string, AchievementConditionEditContext)

    Empties a node slot, leaving the achievement unlocked from code alone.

    Declaration
    public static void ClearDeferred(SerializedObject owner, string nodePath, AchievementConditionEditContext context)
    Parameters
    Type Name Description
    SerializedObject owner

    The serialized object the tree belongs to.

    string nodePath

    Path of the node property to empty.

    AchievementConditionEditContext context

    What the drawer was given to write with.

    MoveChild(SerializedProperty, int, int, AchievementConditionEditContext)

    Moves one child to another position in a composite's list.

    Declaration
    public static void MoveChild(SerializedProperty listProperty, int fromIndex, int toIndex, AchievementConditionEditContext context)
    Parameters
    Type Name Description
    SerializedProperty listProperty

    The composite's child list.

    int fromIndex

    Position of the child to move.

    int toIndex

    Position to move it to. Out-of-range targets are ignored.

    AchievementConditionEditContext context

    What the drawer was given to write with.

    RemoveChildAt(SerializedProperty, int, AchievementConditionEditContext)

    Removes one child from a composite's list.

    Declaration
    public static void RemoveChildAt(SerializedProperty listProperty, int childIndex, AchievementConditionEditContext context)
    Parameters
    Type Name Description
    SerializedProperty listProperty

    The composite's child list.

    int childIndex

    Position of the child to remove.

    AchievementConditionEditContext context

    What the drawer was given to write with.

    Remarks

    Deleted twice when the first delete only emptied the slot: Unity's array delete nulls an element before it removes it for some property kinds, and a tree left holding a null child reads to an author as a node that refuses to go away. Both deletes share the single apply below, so they are already one undo step without a group around them.

    ReplaceDeferred(SerializedObject, string, Type, AchievementConditionEditContext)

    Replaces the node a managed-reference property holds with a new node of the given type, carrying over the children the new shape can hold.

    Declaration
    public static void ReplaceDeferred(SerializedObject owner, string nodePath, Type replacementType, AchievementConditionEditContext context)
    Parameters
    Type Name Description
    SerializedObject owner

    The serialized object the tree belongs to.

    string nodePath

    Path of the node property to replace.

    Type replacementType

    The concrete condition type to put there.

    AchievementConditionEditContext context

    What the drawer was given to write with.

    Remarks

    Works for every slot a node can sit in — the achievement's root condition, a wrapper's inner slot, or one element of a composite's list — because all three are the same kind of managed-reference property. That is also why an empty slot is filled by the same call rather than by a separate "add" path.

    Both serialized writes happen inside one undo group. Replacing the node and re-parenting its children are two applies, and two undo steps would let the author land on a tree holding the new node with none of its children — a state nobody authored.

    In this article
    © 2026 Serenity. All Rights Reserved