Announcement

Collapse
No announcement yet.

UFSM: Finite State Machine

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • replied
    Try change the source code of "Make States" function to something like this and see if the problem still persist:

    Code:
    void UStateMachineComponent::MakeStates(const TArray<FName> &NewStates, FSM_Transition &Transition) {
        if (NewStates.Num()==0) {
            Transition = FSM_Transition::Aborted;
            LOG_FSM(Debug,GetOwner(),this,ESeverity::Error,FString("'New States' Array is zero sized."));
            LOG_PIE(Debug,ESeverity::Error,this,FFIND(TEXT("MakeStates")),FString("'New States' Array is zero sized."));
        return;}
        //
        for (auto &State : STATE) {
            State.Value.OnBeginState.Clear();
            State.Value.OnUpdateState.Clear();
            State.Value.OnExitState.Clear();
        } STATE.Empty();
        //
        for (int32 I=0; I<NewStates.Num(); I++) {
            if (!NewStates[I].IsValid()) {LOG_PIE(Debug,ESeverity::Error,this,FFIND(TEXT("MakeStates")),FString::Printf(TEXT("Name for generated State of index {&i} is invalid."),I)); continue;}
            if (NewStates[I].IsNone()) {LOG_PIE(Debug,ESeverity::Error,this,FFIND(TEXT("MakeStates")),FString::Printf(TEXT("Name for generated State of index {&i} is invalid."),I)); continue;}
            STATE.Add(I,NewStates[I]);
            STATE[I].Owner = this;
        } Transition = FSM_Transition::Succeeded;
        //
        LinkStates();
    }

    If still the same, might be something hidden inside State struct constructor.

    Leave a comment:


  • replied
    For the record I'm doing the state machine stuff entirely in BP. All C++ does is find a reference to the state machine and check the state/set the state in a few cases. The items themselves that make use of the state machine still use a lot of C++.

    As for MakeStates() after FindComponent succeeds it actually calls SetupStateMachine() which calls MakeStates().

    Code:
    void AVESItem::PostInitializeComponents()
    {
        Super::PostInitializeComponents();
    
        StateMachine = FindComponentByClass<UStateMachineComponent>();
        if (StateMachine)
        {
            StateMachine->SetupStateMachine();
        }
    }
    STATES are all valid before and after MakeStates(), it's being invalidated somewhere else.

    And - Awesome, the new nodes look really good
    Last edited by Vaei; 07-04-2018, 07:58 PM.

    Leave a comment:


  • replied
    Vaei


    So, I've added these new nodes and will send updated plugin to Epic soon...





    The situation you describe above could be dealt with doing something like this:






    To avoid wasting time creating Event signatures, instead of creating an Event manually, drag from the new Latent "Finish State" Node and the signature it accepts will automatically apply when you create an Event attached to it:





    Note however that Async nodes won't work inside Function graphs, must be onto main graphs and you can't call them directly from outside the FSM Component's Blueprint...

    The "On Begin Equipping" function should make a call to a custom Event on main Graph to execute the latent Finish node.
    Last edited by BrUnO XaVIeR; 07-04-2018, 07:57 PM.

    Leave a comment:


  • replied
    Originally posted by Vaei View Post
    This occurred again. Last time the only way I could fix it was by rebuilding the state machine from scratch (which isn't happening so I need a solution). Somewhere it has corrupted. I try to delete it and remake the specific state but the issue persists. Now whenever the state is set to 1 it crashes.


    Btw, whenever you change your Array of 'FName' States, add/remove/replace, etc... Make sure you call the "MakeStates()" function.
    There is where State objects are generated and stored in the TMap.
    You can also force the TMap to create a new State object in the problematic index:
    Code:
    STATE.Add(1,TEXT("stateName"));

    _____
    Edit:

    Actually what seems to be invalid is the "Name" variable of your State object in index 1.
    If was the object struct it would've crashed earlier, not in that line.
    Last edited by BrUnO XaVIeR; 07-04-2018, 07:53 PM.

    Leave a comment:


  • replied
    You can loop through the TMap container of States and check for validation... If any is null/invalid create a new State struct and assign to that index.

    Leave a comment:


  • replied
    Originally posted by BrUnO XaVIeR View Post
    What I can do easily, without breaking anything, is implement "latent" versions of "Finish State" BP Node which is used already to invoke Default Transition...

    These nodes can implement the components you mention be needed, timers, callbacks, etc.
    With a combination of properties above to a conditional check, Fsm goes to either State A or B... With a callback to either Event A or Event B.

    It's doable, I will add this to todo list.
    The small annoyance is these nodes are more friendly to Blueprint FSMs and not so much to pure Cpp Components, but will cover the issues well enough.
    ​​​​​
    Sounds good! I don't see myself using it much in C++ anywho, but that's just me.

    Any thoughts on how to fix that corrupt(?) state?

    Leave a comment:


  • replied
    What I can do easily, without breaking anything, is implement "latent" versions of "Finish State" BP Node which is used already to invoke Default Transition...

    These nodes can implement the components you mention be needed, timers, callbacks, etc.
    With a combination of properties above to a conditional check, Fsm goes to either State A or B... With a callback to either Event A or Event B.

    It's doable, I will add this to todo list.
    The small annoyance is these nodes are more friendly to Blueprint FSMs and not so much to pure Cpp Components, but will cover the issues well enough.
    ​​​​​

    Leave a comment:


  • replied
    Originally posted by BrUnO XaVIeR View Post
    State object in TMap index 1 for some reason is null.
    How are you creating States list?
    Somewhere in the process index 1 is ignored when you create them.

    _____

    Btw, you can force State creation with:
    Code:
    StateMachine->AddState(1,FName("stateName"));
    But I'd rather examine Blueprints and identify why this one in particular isn't being created in your setup...

    You may have duplicate State names or related issue; now that TSet is supported by Blueprints I should convert name list from Array to Set, but that deprecation process is annoying so I may only do that for 2.0+ version on Unreal 4.20+.
    ​​​​​
    I could construct an exact duplicate of this state machine from scratch and it will work. That's how I fixed it last time. Feels like something is corrupting internally.

    I'm creating the states by simply adding to the array. I made an enum and provided that instead but no difference.





    On an unrelated note since you mention 2.0 can I make a suggestion/request?

    In the screenshot provided for the issue, you can see that some states are actually transitions, eg. "Equipped" is a state and "Equipping" is a transition; during "Equipping" state there is an animation playing, a sound, a material effect and when the duration expires it goes to Equipped.

    And then the "FSM Default Links" already has a state that it transitions to when Finish State is called. For transitions that can go one way or the other, they'd need a BlueprintNativeEvent that takes the next state as an argument.

    So basically, the idea is that the FSM Default Links could also have a 'Duration' set, when the Duration expires it transitions to the NextState. Furthermore, these could have a BlueprintImplementableEvent (or native if needed) that return the next state to transition to - so for example my "PickingUp" state is a transition that either goes to "Equipping" (if it can be equipped and nothing is equipped there) or "Unequipped" (in inventory), in which case I'd check it's destination in that function and return the "Equipping" or "Unequipped" state based on that.

    If this does happen, it might be worth having an interrupted call back, if finish state or begin state was called part way through a transition. Also, when starting a state or transition from an interrupted transition it could be worth having the left-over time.
    Last edited by Vaei; 07-04-2018, 01:50 AM.

    Leave a comment:


  • replied
    State object in TMap index 1 for some reason is null.
    How are you creating States list?
    Somewhere in the process index 1 is ignored when you create them.

    _____

    Btw, you can force State creation with:
    Code:
    StateMachine->AddState(1,FName("stateName"));
    But I'd rather examine Blueprints and identify why this one in particular isn't being created in your setup...

    You may have duplicate State names or related issue; now that TSet is supported by Blueprints I should convert name list from Array to Set, but that deprecation process is annoying so I may only do that for 2.0+ version on Unreal 4.20+.
    ​​​​​
    Last edited by BrUnO XaVIeR; 07-02-2018, 05:13 PM.

    Leave a comment:


  • replied
    This occurred again. Last time the only way I could fix it was by rebuilding the state machine from scratch (which isn't happening so I need a solution). Somewhere it has corrupted. I try to delete it and remake the specific state but the issue persists. Now whenever the state is set to 1 it crashes.

    Leave a comment:


  • replied
    Originally posted by Vaei View Post
    As a heads up or for anyone reading over this, the code you provided here wasn't resetting the state time, and I don't need to replicate that since the state itself is being replicated so:

    Code:
    void UStateMachineComponent::OnREP_StateID_Implementation(uint8 &ID)
    {
        ID = StateID;
    
        FSM_Transition Transition = FSM_Transition::Succeeded;
        Exit(PreviousStateID, ID, Transition, InExit);
        Enter(ID, InBegin);
        StateTime = 0.f;
    
        if (Transition != FSM_Transition::Succeeded)
        {
            LOG_PIE(Debug, ESeverity::Warning, this, FFIND(TEXT("OnREP_StateID")), FString("[OnREP_StateID]: Exiting 'PreviousStateID' was aborted."));
        }
    }

    Good practice would be also check if it actually replicates, like:
    Code:
    if ( !ReplicateStateTime ) {  StateTime = 0.f;  }

    Leave a comment:


  • replied
    I just had a typed variable for the state and I was setting it with a dropdown. Then when I was setting the state it was converting it into a name, so yeah probably. Normally that conversion works but I guess there's a UE limitation in there.

    Leave a comment:


  • replied
    Hmm...
    Are you comparing States to enum names??
    Unreal internally names BP Enums like that: "enum::itemname".

    I wouldn't compare States to bp enum names, weird things like that might happen; I'd only use them to "copy" States quickly into the States array, specially because the way Epic serializes BP Enums into assets (they aren't real enums).

    If you're getting the "name" of a BP Enum item it will output something like that (the internal name of item) instead of the display name you see in Blueprint Graphs.

    Leave a comment:


  • replied
    Originally posted by BrUnO XaVIeR View Post
    It just means it wasn't checked to exist or not.
    This "Unchecked" thing is there because there's people adding/removing replicated States at game runtime...

    But it shouldn't do that for the startup, I will look tomorrow to see that is happening.
    Would there be other people or replication in a non-multiplayer game?

    Oh, got it. Somehow component auto-activate was unchecked. Probably from the plugin being disabled.

    Back to the original issue:

    Code:
    PIE: Warning: {FSM}:: 'Set State' named [EAIState::NewEnumerator9]: State ID doesn't exist. -->  FSM: Set State: [Function /Script/UFSM.StateMachineComponent:SetState at (StateMachineComponent /Game/AvGaHo/Maps/UEDPIE_0_Map_Bull.Map_Bull:PersistentLevel.PC_Bull_2.StateMachine)]
    FSMs: Warning: [StateMachine]: 'Set State' named [EAIState::NewEnumerator9]: State ID doesn't exist.
    This is weird. My enum name isn't "NewEnumerator9" and the type is right. I guess I'll just store it as a name instead.

    Leave a comment:


  • replied
    Originally posted by Antidamage View Post
    I finally got the plugin update installed.

    I'm getting a new issue - the startup state is being ignored and it's just using the first state in the enum.

    If I force the state on BeginPlay it returns "unchecked". What does this result actually mean? There's nothing in the output panel.
    I can't reproduce what you report.
    Did you try clean up the "FSM States" array and input your Enum BP again?

    Every time here the startup State is what set it to be...

    Leave a comment:

Working...
X