{.experimental: "codeReordering".} import ../drawable/[ shape_object ] , ../vk/[ vulkan_record , vulkan ] , std/[ math ] , actions , options , tables ### state machine stuff type # entry_action: Option[Callback] # exit_action: Option[Callback] State_Actions = tuple[ entry_action: Option[Callback] , exit_action: Option[Callback] ] Callback = proc(deshn_being: var Deshn_Being): void StateEvent[S,E] = tuple[state: S, event: E] Transition[S] = tuple[nextState: S, action: Option[Callback]] State_Machine*[S,E] = ref object of RootObj initial_state*: S current_state*: Option[S] state_actions*: array[S, StateActions] transitions*: TableRef[StateEvent[S,E], Transition[S]] free_transitions*: TableRef[S, Transition[S]] default_transition*: Option[Transition[S]] #TransitionNotFoundException = object of Exception proc current_state_is*[S]( being: var Deshn_Being , nextState: S ) = if being.main_state_machine.current_state.isSome: if being.main_state_machine.state_actions[being.main_state_machine.current_state.get].exit_action.isSome: get(being.main_state_machine.state_actions[being.main_state_machine.current_state.get].exit_action)(being) being.main_state_machine.current_state = some(nextState) if being.main_state_machine.state_actions[being.main_state_machine.current_state.get].entry_action.isSome: get(being.main_state_machine.state_actions[being.main_state_machine.current_state.get].entry_action)(being) proc reset*[S,E]( being: var Deshn_Being ) = being.main_state_machine.current_state_is being.main_state_machine.initial_state proc initial_state_is*[S,E]( m: State_Machine[S,E] , state: S ) = m.initialState = state proc initial_state_is*[S,E]( being: var Deshn_Being , state: S ) = being.main_state_machine.initial_state = state proc add_state_actions*[S]( being: var Deshn_Being , state: S , entry_action: Callback = nil , exit_action: Callback = nil ) = let entry = if entry_action == nil: none(Callback) else: some(entry_action) exit = if exit_action == nil: none(Callback) else: some(exit_action) being.main_state_machine.state_actions[state] = (entry, exit) proc a_state_machine*[S,E]( initial_state: S ): State_Machine[S,E] = result = State_Machine[S,E]() result.transitions = newTable[ StateEvent[S,E] , Transition[S] ]() result.free_transitions = newTable[ S , Transition[S] ]() result.initial_state_is initial_state proc add_free_transition*[S,E]( being: var Deshn_Being , state: S, nextState: S ) = being.main_state_machine.free_transitions[state] = (nextState, none(Callback)) proc addTransitionAny*[S,E]( being: var Deshn_Being , state, nextState: S , action: Callback ) = being.main_state_machine.free_transitions[state] = (nextState, some(action)) proc add_transition*[S,E]( being: var Deshn_Being , state: S , event: E , nextState: S ) = being.main_state_machine.transitions[(state, event)] = (nextState, none(Callback)) proc add_transition*[S,E]( being: var Deshn_Being , state: S , event: E , nextState: S , action: Callback ) = being.main_state_machine.transitions[(state, event)] = (nextState, some(action)) proc setDefaultTransition*[S,E]( being: var Deshn_Being , state: S ) = being.main_state_machine.default_transition = some((state, none(Callback))) proc setDefaultTransition*[S,E]( being: var Deshn_Being , state: S , action: Callback ) = being.main_state_machine.default_transition = some((state, some(action))) proc the_transition*[S,E]( being: var Deshn_Being , event: E , state: S ): Transition[S] = let map = (state, event) if being.main_state_machine.transitions.hasKey(map): result = being.main_state_machine.transitions[map] elif being.main_state_machine.free_transitions.hasKey(state): result = being.main_state_machine.free_transitions[state] elif being.main_state_machine.default_transition.isSome: result = being.main_state_machine.default_transition.get else: echo map quit "Transition not found" proc process_event*[E]( being: var Deshn_Being , event: E ) = let transition = being.the_transition( event , being.main_state_machine.current_state.get ) #echo "t0: ", transition[0] if transition[1].isSome: get(transition[1])(being) being.current_state_is transition[0] #echo event, " ", being.main_state_machine.current_state.get ### TODO: PLEASE SORT THIS OUT ^^^^^^^^^^^^^ type Main_Deshn_Being_Events* = enum Moved No_Action Added_To_Deshn_Pool Removed_From_Deshn_Pool Added_To_Recovery_Pool Removed_From_Recovery_Pool Filled_Deshn_Pool Exhausted_Deshn_Pool Filled_Recovery_Pool Exhausted_Recovery_Pool Stopped Main_Deshn_Being_States* = enum Moving Not_Moving Recovering Idle Deshn_Pool_Full #Deshn_Pool_Not_Full Deshn_Pool_Empty Deshn_Pool_Emptying Deshn_Pool_Filling Deshn_Pool_Exhausted Deshn_Pool_Value* = range[0.0..30.0] Deshn_Recovery_Pool_Value* = range[0.0..2.0] Deshn_Being_Obj = object of RootObj shape*: Shape current_deshn_pool*: float32 = 30 current_deshn_pool_max_size*: Deshn_Pool_Value = Deshn_Pool_Value.high current_deshn_pool_recovery_pool*: Deshn_Recovery_Pool_Value = Deshn_Recovery_Pool_Value.high current_deshn_pool_recovery_pool_max*: Deshn_Recovery_Pool_Value = Deshn_Recovery_Pool_Value.high recovering*: bool name*: string id*: int main_state_machine*: State_Machine[ Main_Deshn_Being_States , Main_Deshn_Being_Events ] Deshn_Being* = ref object of Deshn_Being_Obj proc deshn_pool_is_full*( being: Deshn_Being ): bool = return being.shape.ubo.deshn_pool_is_full proc deshn_pool_is_empty*( being: Deshn_Being ): bool = return being.shape.ubo.deshn_pool_is_empty proc can_move*( being: var Deshn_Being ): bool = return ( not being.deshn_pool_is_empty() and being.current_deshn_pool_recovery_pool == Deshn_Recovery_Pool_Value.high ) proc add_amount_to_deshn_pool*( being: var Deshn_Being , amount: float32 ) = being.shape.ubo.deshn_pool += amount being.shape.ubo.deshn_pool_is_empty = false echo being.shape.ubo.deshn_pool being.process_event Main_Deshn_Being_Events.Added_To_Deshn_Pool if being.shape.ubo.deshn_pool >= being.current_deshn_pool_max_size: being.main_state_machine.current_state = some Deshn_Pool_Full being.shape.ubo.deshn_pool_is_full = true #[ #if not being.shape.ubo.deshn_pool_is_full: if not (being.main_state_machine.current_state_is Pool_Full) being.shape.ubo.deshn_pool += amount #if being.shape.ubo.deshn_pool_is_empty: if (being.main_state_machine.current_state_is Pool) being.shape.ubo.deshn_pool_is_empty = false being.shape.ubo.deshn_pool += amount if being.shape.ubo.deshn_pool >= being.current_deshn_pool_max_size: being.shape.ubo.deshn_pool_is_full = true being.shape.ubo.deshn_pool = Deshn_Pool_Value.high ]# proc remove_amount_from_deshn_pool*( being: var Deshn_Being , amount: float32 ) = being.shape.ubo.deshn_pool -= amount being.process_event Main_Deshn_Being_Events.Removed_From_Deshn_Pool being.shape.ubo.deshn_pool_is_full = false if being.shape.ubo.deshn_pool <= Deshn_Pool_Value.low: being.recovering = true being.shape.ubo.deshn_pool_is_empty = true being.process_event Main_Deshn_Being_Events.Exhausted_Deshn_Pool proc add_amount_to_recovery_pool*( being: var Deshn_Being , amount: float32 ) = if (being.current_deshn_pool_recovery_pool + amount > Deshn_Recovery_Pool_Value.high) or being.current_deshn_pool_recovery_pool >= Deshn_Recovery_Pool_Value.high: being.current_deshn_pool_recovery_pool = Deshn_Recovery_Pool_Value.high being.process_event Added_To_Recovery_Pool being.process_event Filled_Recovery_Pool else: being.current_deshn_pool_recovery_pool += amount being.process_event Added_To_Recovery_Pool proc remove_amount_from_recovery_pool*( being: var Deshn_Being , amount: float32 ) = being.current_deshn_pool_recovery_pool -= amount if being.current_deshn_pool_recovery_pool <= Deshn_Recovery_Pool_Value.low: being.current_deshn_pool_recovery_pool = Deshn_Recovery_Pool_Value.low being.recovering = true proc idle_and_moved_cb( deshn_being: var Deshn_Being) = echo "idle and moved" proc not_moving_and_moved_cb( deshn_being: var Deshn_Being) = echo "stopped and moved" proc moving_and_no_action_cb( deshn_being: var Deshn_Being) = echo "moving and no action" proc stopped_and_no_action_cb( deshn_being: var Deshn_Being) = echo "stopped and no action" proc deshn_pool_full_and_taken_from_cb( deshn_being: var Deshn_Being) = echo "full pool taken from" deshn_being.shape.ubo.deshn_pool_is_full = false proc deshn_pool_empty_and_added_to_cb( deshn_being: var Deshn_Being) = echo "empty pool added to" deshn_being.shape.ubo.deshn_pool_is_empty = false proc deshn_pool_filling_and_added_to_cb( deshn_being: var Deshn_Being) = echo "pool filling added to" proc deshn_pool_filling_and_full_cb( deshn_being: var Deshn_Being) = echo "pool added to and now full" deshn_being.shape.ubo.deshn_pool_is_full = true proc deshn_pool_full_and_moved_cb( deshn_being: var Deshn_Being) = echo "pool full and moved" deshn_being.shape.ubo.deshn_pool_is_full = false proc deshn_pool_empyting_and_stopped( deshn_being: var Deshn_Being) = echo "pool emptying and now stopped" proc moving_and_exhausted_pool_cb( deshn_being: var Deshn_Being) = echo "moving and exhausted pool" proc exhausted_pool_and_no_action_cb( deshn_being: var Deshn_Being) = echo "exhausted pool and no action" proc deshn_pool_emptying_and_taken_from_cb( deshn_being: var Deshn_Being) = echo "pool emptying and taken from" if deshn_being.shape.ubo.deshn_pool <= Deshn_Pool_Value.low: deshn_being.shape.ubo.deshn_pool = Deshn_Pool_Value.low deshn_being.current_deshn_pool = Deshn_Pool_Value.low deshn_being.shape.ubo.deshn_pool_is_empty = true proc deshn_pool_empty_and_taken_from_cb( deshn_being: var Deshn_Being) = echo "pool empty and taken from" proc deshn_pool_exhausted_and_no_action_cb( deshn_being: var Deshn_Being) = echo "pool exhausted, no action" proc deshn_pool_exhausted_and_added_to_cb( deshn_being: var Deshn_Being) = echo "deshn_pool_exhausted_and_added_to_cb" if deshn_being.current_deshn_pool_recovery_pool >= Deshn_Recovery_Pool_Value.high: deshn_being.current_deshn_pool_recovery_pool = Deshn_Recovery_Pool_Value.high deshn_being.recovering = false proc recovering_and_added_to_recovery_pool_cb( deshn_being: var Deshn_Being) = echo "recovering_and_added_to_recovery_pool_cb" proc moving_and_taken_from_pool_cb( deshn_being: var Deshn_Being) = echo "moving, taken X from pool" if deshn_being.shape.ubo.deshn_pool <= Deshn_Pool_Value.low: deshn_being.shape.ubo.deshn_pool = Deshn_Pool_Value.low deshn_being.current_deshn_pool_recovery_pool = Deshn_Recovery_Pool_Value.low deshn_being.shape.ubo.deshn_pool_is_empty = true proc moving_and_moved_cb( deshn_being: var Deshn_Being) = echo "moving, and moved" proc not_moving_and_added_to_pool_cb( deshn_being: var Deshn_Being) = echo "not_moving_and_added_to_pool" proc moving_and_added_to_pool_cb( deshn_being: var Deshn_Being) = echo "moving_and_added_to_pool" proc deshn_pool_filling_and_moved_cb( deshn_being: var Deshn_Being) = echo "deshn_pool_filling_and_moved_cb" proc filled_recovery_pool_and_now_idle_cb( deshn_being: var Deshn_Being) = echo "filled_recovery_pool_and_now_idle_cb" deshn_being.recovering = false proc idle_and_added_to_deshn_pool_cb( deshn_being: var Deshn_Being) = echo "idle_and_added_to_deshn_pool_cb" proc when_moving_state_action( deshn_being: var Deshn_Being) = discard proc after_moving_state_action( deshn_being: var Deshn_Being ) = discard proc when_not_moving_state_action( deshn_being: var Deshn_Being) = discard proc after_not_moving_state_action( deshn_being: var Deshn_Being ) = discard proc when_recovering_state_action( deshn_being: var Deshn_Being ) = discard proc after_recovering_state_action( deshn_being: var Deshn_Being ) = discard proc when_stopped_state_action( deshn_being: var Deshn_Being ) = discard proc after_stopped_state_action( deshn_being: var Deshn_Being ) = discard proc when_idle_state_action( deshn_being: var Deshn_Being ) = discard proc after_idle_state_action( deshn_being: var Deshn_Being ) = discard proc when_deshn_pool_full_state_action( deshn_being: var Deshn_Being ) = discard proc after_deshn_pool_full_state_action( deshn_being: var Deshn_Being ) = discard proc when_deshn_pool_empty_state_action( deshn_being: var Deshn_Being ) = discard proc after_deshn_pool_empty_state_action( deshn_being: var Deshn_Being ) = discard proc when_deshn_pool_emptying_state_action( deshn_being: var Deshn_Being ) = discard proc after_deshn_pool_emptying_state_action( deshn_being: var Deshn_Being ) = discard proc when_deshn_pool_filling_state_action( deshn_being: var Deshn_Being ) = discard proc after_deshn_pool_filling_state_action( deshn_being: var Deshn_Being ) = discard proc when_deshn_pool_exhausted_state_action( deshn_being: var Deshn_Being ) = discard proc after_deshn_pool_exhausted_state_action( deshn_being: var Deshn_Being ) = discard proc add_default_transitions*( being: var Deshn_Being ) = being.add_transition( Idle , Moved , Moving , idle_and_moved_cb ) being.add_transition( Not_Moving , Moved , Moving , not_moving_and_moved_cb ) being.add_transition( Moving , No_Action , Not_Moving , moving_and_no_action_cb ) being.add_transition( Not_Moving , No_Action , Idle , stopped_and_no_action_cb ) being.add_transition( Deshn_Pool_Full , Removed_From_Deshn_Pool , Deshn_Pool_Emptying , deshn_pool_full_and_taken_from_cb ) being.add_transition( Deshn_Pool_Empty , Added_To_Deshn_Pool , Deshn_Pool_Filling , deshn_pool_empty_and_added_to_cb ) being.add_transition( Deshn_Pool_Filling , Added_To_Deshn_Pool , Deshn_Pool_Filling , deshn_pool_filling_and_added_to_cb ) being.add_transition( Deshn_Pool_Emptying , Removed_From_Deshn_Pool , Deshn_Pool_Empty , deshn_pool_emptying_and_taken_from_cb ) being.add_transition( Deshn_Pool_Exhausted , No_Action , Recovering , deshn_pool_exhausted_and_no_action_cb ) being.add_transition( Deshn_Pool_Exhausted , Added_To_Recovery_Pool , Recovering , deshn_pool_exhausted_and_added_to_cb ) being.add_transition( Moving , Removed_From_Deshn_Pool , Moving , moving_and_taken_from_pool_cb ) being.add_transition( Moving , Moved , Moving , moving_and_moved_cb ) being.add_transition( Moving , Stopped , Not_Moving , moving_and_moved_cb ) being.add_transition( Not_Moving , Added_To_Deshn_Pool , Deshn_Pool_Filling , not_moving_and_added_to_pool_cb ) being.add_transition( Deshn_Pool_Full , Moved , Moving , deshn_pool_full_and_moved_cb ) being.add_transition( Moving , Added_To_Deshn_Pool , Moving , moving_and_added_to_pool_cb ) #[ being.add_transition( Deshn_Pool_Full , Moved , Deshn_Pool_Not_Full , deshn_pool_full_and_moved_cb ) ]# #[ being.add_transition( Deshn_Pool_Not_Full , Removed_From_Deshn_Pool , Deshn_Pool_Emptying , deshn_pool_not_full_and_removed_from_cb ) ]# being.add_transition( Deshn_Pool_Emptying , Stopped , Not_Moving , deshn_pool_empyting_and_stopped ) being.add_transition( Deshn_Pool_Filling , Moved , Moving , deshn_pool_filling_and_moved_cb ) being.add_transition( Moving , Exhausted_Deshn_Pool , Deshn_Pool_Exhausted , moving_and_exhausted_pool_cb ) being.add_transition( Deshn_Pool_Exhausted , No_Action , Recovering , exhausted_pool_and_no_action_cb ) being.add_transition( Recovering , Added_To_Recovery_Pool , Recovering , exhausted_pool_and_no_action_cb ) being.add_transition( Idle , Added_To_Deshn_Pool , Deshn_Pool_Filling , idle_and_added_to_deshn_pool_cb ) being.add_transition( Recovering , Filled_Recovery_Pool , Idle , filled_recovery_pool_and_now_idle_cb ) proc add_default_state_actions*( being: var Deshn_Being ) = being.add_state_actions( Moving , entry_action = when_moving_state_action , exit_action = after_moving_state_action ) being.add_state_actions( Recovering , entry_action = when_recovering_state_action , exit_action = after_recovering_state_action ) being.add_state_actions( Not_Moving , entry_action = when_stopped_state_action , exit_action = after_stopped_state_action ) being.add_state_actions( Idle , entry_action = when_idle_state_action , exit_action = after_idle_state_action ) #[ being.add_state_actions( Deshn_Pool_Exhausted , entry_action = when_deshn_pool_exhausted_state_action , exit_action = after_deshn_pool_exhausted_state_action ) ]# being.add_state_actions( Deshn_Pool_Empty , entry_action = when_deshn_pool_empty_state_action , exit_action = after_deshn_pool_empty_state_action ) being.add_state_actions( Deshn_Pool_Emptying , entry_action = when_deshn_pool_emptying_state_action , exit_action = after_deshn_pool_emptying_state_action ) being.add_state_actions( Deshn_Pool_Filling , entry_action = when_deshn_pool_filling_state_action , exit_action = after_deshn_pool_filling_state_action ) being.add_state_actions( Deshn_Pool_Full , entry_action = when_deshn_pool_full_state_action , exit_action = after_deshn_pool_full_state_action ) being.add_state_actions( Not_Moving , entry_action = when_not_moving_state_action , exit_action = after_not_moving_state_action ) proc a_deshn_being*( shape: Shape , name: string ): Deshn_Being = result = Deshn_Being() result.shape = shape result.name = name result.main_state_machine = a_state_machine[ Main_Deshn_Being_States , Main_Deshn_Being_Events ](Idle) result.add_default_transitions() result.add_default_state_actions()