{.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()