Announcement

Collapse
No announcement yet.

UFSM: Finite State Machine

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

    Ah that's not what I'm after and the MP is actually really good! I don't want to use multicast because he's more costly and unnecessary and not absolutely time critical in my usage (which is where multicast is warranted)

    The server and owning client run the same logic and I use server and client RPC to do that. If the client calls an RPC then it follows the local execution and instructs the server to do the same. However if the server calls the RPC to the client it doesn't follow the local execution, it just instructs the client to call theirs and the initial pattern comes into play . Because the client leads the execution every time in theory there is no desynchronization other than fringe cases that are handled with an extra rpc ensuring the result is identical.

    The result is that the server and owning client run the same code safely and reliably. All that remains is the remote clients which don't need to run any of that code, they just need to obtain the result from the server (and never the owning client).

    To send the result to the simulated clients I don't want to rpc as it's unnecessary and for this case, wasteful . All I need is the resulting state to replicate from the server and when the state is set via replication the corresponding function is expected (i.e begin state, update state, etc)

    Does it make sense? It's hard to type on this phone

    Comment


      If they, simul clients, are receiving replicated ID correctly then I would try to call the normal "offline" Set State node in the overriden OnREP ID function.

      This way every time Server changes State they simply take resulting ID and apply that same State locally.

      That is necessary because OnREP will never invoke anywhere Enter() or Update() or Exit(), internal Fsm functions.
      Last edited by BrUnO XaVIeR; 06-21-2018, 04:07 AM.
      | Savior | USQLite | FSM | Object Pool | Sound Occlusion | Property Transfer | Magic Nodes | MORE |

      Comment


        Originally posted by BrUnO XaVIeR View Post
        If they, simul clients, are receiving replicated ID correctly then I would try to call the normal "offline" Set State node in the overriden OnREP ID function.

        This way every time Server changes State they simply take resulting ID and apply that same State locally.

        That is necessary because OnREP will never invoke anywhere Enter() or Update() or Exit(), internal Fsm functions.
        The 'Aborted' callback is the result when I do that

        Comment


          Originally posted by Vaei View Post

          The 'Aborted' callback is the result when I do that
          I am testing this as well.
          Seems like the OnREP_StateID_Implementation has a bug when it is overriden by the GeneratedClass.

          I will see if I can fix that by manually adding Exit(PreviousID) then call Enter(StateID) from within the native C++ OnREP_ function instead;
          That may resolve the issue.
          | Savior | USQLite | FSM | Object Pool | Sound Occlusion | Property Transfer | Magic Nodes | MORE |

          Comment


            Vaei I have fixed that problem here in my Component doing these changes to the native OnREP_ functions:

            Code:
            void UStateMachineComponent::OnREP_StateID_Implementation(uint8 &ID) {
            
                ID = StateID;
            
                FSM_Transition Transition = FSM_Transition::Succeeded;
                Exit(PreviousStateID,ID,Transition,InExit);
                Enter(ID,InBegin);
            
                if ( Transition != FSM_Transition::Succeeded ) {
                    LOG_PIE(Debug,ESeverity::Warning,this,FFIND(TEXT("OnREP_StateID")),FString("[OnREP_StateID]: Exiting 'PreviousStateID' was aborted."));
                }
            
            }
            
            void UStateMachineComponent::OnREP_StateTime_Implementation(float &Time) {
                Time = StateTime;
            }
            
            void UStateMachineComponent::OnREP_PreviousStateID_Implementation(uint8 &PreviousID) {
                PreviousID = PreviousStateID;
            }
            Doing that instantly fixed here all my Components containing overriden OnREP_StateID function.
            | Savior | USQLite | FSM | Object Pool | Sound Occlusion | Property Transfer | Magic Nodes | MORE |

            Comment


              Are you sure Epic have released the update? I've been restarting the launcher but I'm yet to see an update to the plugin come through.

              To be double sure I enabled debug and I'm trying to get some info out. The state I'm trying to set isn't showing up as failed (or at all). So far all I see is normal looking stuff:

              Code:
              PIE: Warning: {FSM}:: ''Blueprint Auto Flow FSM'' is enabled; Trying to invoke ''On Begin'' for (OpeningCharge) State, but (OnBeginOpeningCharge) function have not been found! -->  Begin: [Function /Script/UFSM.StateMachineComponent:Begin at (StateMachineComponent /Game/AvGaHo/Maps/UEDPIE_0_Map_Bull.Map_Bull:PersistentLevel.PC_Bull_2.StateMachine)]
              PIE: Warning: {FSM}:: ''Blueprint Auto Flow FSM'' is enabled; Trying to invoke ''On Exit'' for (OpeningCharge) State, but (OnExitOpeningCharge) function have not been found! -->  Exit: [Function /Script/UFSM.StateMachineComponent:Exit at (StateMachineComponent /Game/AvGaHo/Maps/UEDPIE_0_Map_Bull.Map_Bull:PersistentLevel.PC_Bull_2.StateMachine)]
              PIE: Warning: {FSM}:: ''Blueprint Auto Flow FSM'' is enabled; Trying to invoke ''On Begin'' for (EmergencyStop) State, but (OnBeginEmergencyStop) function have not been found! -->  Begin: [Function /Script/UFSM.StateMachineComponent:Begin at (StateMachineComponent /Game/AvGaHo/Maps/UEDPIE_0_Map_Bull.Map_Bull:PersistentLevel.PC_Bull_2.StateMachine)]
              Maybe I'm doing something else wrong? I've set up a call to queue a future state, then when the current activity is finished it switches to that state:



              The execution chain is: it starts with OpeningCharge, has Stare set as the future state and then EmergencyStop executes when it reaches the edge of the play area. When it calls emergency stop it waits for a moment then calls the event to set the next state, which is when it aborts.
              Last edited by Antidamage; 06-22-2018, 08:53 AM.

              Comment


                Weird. Here the update is marked as processed.

                Btw, that warning doesn't mean the State isn't set.
                That warning means that State doesn't have generated functions for it on the "StateMachine" FSMBlueprint attached to PC_Bull_2.

                When entering "OpeningCharge" State it calls "OnBeginOpeningCharge()" UFunction, but you didn't create that one UFunction for the State to run.

                After you add new States to the FSM Component Blueprint, hit "+Functions" on its details panel to generate missing UFunctions.
                Last edited by BrUnO XaVIeR; 06-22-2018, 10:18 AM.
                | Savior | USQLite | FSM | Object Pool | Sound Occlusion | Property Transfer | Magic Nodes | MORE |

                Comment


                  I'm not using those functions, it's just that it was the only output. I guess I definitely don't have the update then.

                  Comment


                    Originally posted by BrUnO XaVIeR View Post
                    Vaei I have fixed that problem here in my Component doing these changes to the native OnREP_ functions:

                    Code:
                    void UStateMachineComponent::OnREP_StateID_Implementation(uint8 &ID) {
                    
                    ID = StateID;
                    
                    FSM_Transition Transition = FSM_Transition::Succeeded;
                    Exit(PreviousStateID,ID,Transition,InExit);
                    Enter(ID,InBegin);
                    
                    if ( Transition != FSM_Transition::Succeeded ) {
                    LOG_PIE(Debug,ESeverity::Warning,this,FFIND(TEXT("OnREP_StateID")),FString("[OnREP_StateID]: Exiting 'PreviousStateID' was aborted."));
                    }
                    
                    }
                    
                    void UStateMachineComponent::OnREP_StateTime_Implementation(float &Time) {
                    Time = StateTime;
                    }
                    
                    void UStateMachineComponent::OnREP_PreviousStateID_Implementation(uint8 &PreviousID) {
                    PreviousID = PreviousStateID;
                    }
                    Doing that instantly fixed here all my Components containing overriden OnREP_StateID function.
                    Thank you!

                    But did you mean to use Begin() and not Enter()? Enter() doesn't exist

                    Comment


                      I changed it to Begin() and it's still not being set for simulated proxies. The function runs just fine, aborted isn't called, but the state name with debug still shows the old one.

                      Comment


                        Originally posted by Vaei View Post
                        I changed it to Begin() and it's still not being set for simulated proxies. The function runs just fine, aborted isn't called, but the state name with debug still shows the old one.
                        In 1.8.5 Begin() was renamed Enter().
                        Not all the public UFunctions, just this internal CPP "Begin()" has been renamed.

                        I set the Replication Mode to "None" (Replicates to Everyone) on FSM Component's Details Panel; this way all Clients here receive OnREP_ calls when StateID changes.
                        | Savior | USQLite | FSM | Object Pool | Sound Occlusion | Property Transfer | Magic Nodes | MORE |

                        Comment


                          Originally posted by BrUnO XaVIeR View Post

                          In 1.8.5 Begin() was renamed Enter().
                          Not all the public UFunctions, just this internal CPP "Begin()" has been renamed.

                          I set the Replication Mode to "None" (Replicates to Everyone) on FSM Component's Details Panel; this way all Clients here receive OnREP_ calls when StateID changes.
                          Thanks so much for your assistance.

                          For my latter test I had it set on an item's begin play, at which point the state machine wasn't initialized and as such the begin/exit doesn't work until then, so even though it replicated it wasn't setting the state.

                          Need a graceful workaround but I'll think about it tomorrow

                          Comment


                            You can use "OnInitialized" event on the FSM Component instead of Begin Play.
                            | Savior | USQLite | FSM | Object Pool | Sound Occlusion | Property Transfer | Magic Nodes | MORE |

                            Comment


                              So.. basically.. I can't solve it. I've already solved this issue previously for my items, but I can't with the state machine.

                              The server has the state set correctly. The clients never do for anything that was set prior to the state machine's initialization. I can even force their replication again after initialization and they still don't receive the correct state.

                              I'm suspecting that whatever the issue is originates from this incredibly odd initialization routine. Why isn't the state machine initialized following the completion of PostInitializeComponents? By the time BeginPlay is called it should have long since been initialized. It doesn't make sense that a component isn't fully initialized at that point and goes against UE4's architecture.

                              Should be
                              1. Component Initializes
                              2. ??
                              3. Begin Play

                              Is Actually
                              1. Begin Play
                              2. Replication occurs and nothing works because SM isn't initialized
                              3. Component Initializes

                              I've been beating my head against the wall for hours and I don't know how else to fix it because I've already implemented the fixes and they don't work in this single case.
                              Last edited by Vaei; 06-23-2018, 07:17 PM.

                              Comment


                                It is done this way because AnimBP syncing.
                                Since you apparently aren`t using that sync, I believe you can remove that logic from BeginPlay and place it where it fits your code:
                                Code:
                                FSM_Transition Transition;
                                MakeStates(STATES,Transition);
                                
                                InitializeFSM();
                                You can call that sequence anywhere needed. It's placed there in BeginPlay because, again, AnimBP State syncing.
                                | Savior | USQLite | FSM | Object Pool | Sound Occlusion | Property Transfer | Magic Nodes | MORE |

                                Comment

                                Working...
                                X