Help with extending MAP
Monkey Forums/Monkey Beginners/Help with extending MAP
| ||
I have been trying to create a FSM Manager that will allow me to create FSM's for any objects and add/ execute states on the FSM's. The Idea is any class I need a FSM on I implement IFsmObject ( all code is below) I can then register states against this object: FSM.GetInstance().RegisterState(Self, "normal", New NormalState()) Basic FsmState Class NormalState Extends FsmState Method ExecuteState:String(obj:IFsmObject) Return "" End End This seems to work OK if the IFsmObjects are the same type but as soon as I add a new type of object that implements IFsmObject with Register it looks like it somehow uses that same object type. Could be my Extension of Map or something else ! any ideas ? #REM summary: A FsmMap is a convenience class for mapping IFsmObject objects to StringMap<FsmState>. #END Class FsmMap<V> Extends Map<IFsmObject, V> Method Compare:Int(lhs:IFsmObject, rhs:IFsmObject) If lhs = rhs Return 0 Return 1 End End '------------------------------------------------------------------------------------ #REM summary: interface that defines required properties for a Finite State Machine. #END '------------------------------------------------------------------------------------ Interface IFsmObject Method CurrentState:FsmState() Property Method CurrentState:Void(state:FsmState) Property Method PreviousState:FsmState() Property Method PreviousState:Void(state:FsmState) Property End #REM summary:Abstract class that defines the basic State structure for Finite State Machines. Classes that Extend FsmState must implement ExscuteState #END Class FsmState Abstract Private Field stateName:String Public Method StateName:String() Property Return Self.stateName End Method StateName:Void(stateName:String) Property Self.stateName = stateName End Method EnterState:Void(obj:IFsmObject) End Method ExitState:Void(obj:IFsmObject) End Method ExecuteState:String(obj:IFsmObject) Abstract End Strict #REFLECTION_FILTER+="fsm" Import reflection '------------------------------------------------------------------------------------ #Rem summary:The main singleton Finite State Machine manager Class. The purpose of this Class is To create and manage all FSMState states for all IFSMObject Finite State Machines. Individual states are instantiated and hashed on a per-FSM basis. The FSM class will also handle transitions and call all the neccesary transition callbacks on based on the specifications of individual states. #End Class FSM Private Global instance:FSM = Null Field stateHash:FsmMap<StringMap<FsmState>> = New FsmMap<StringMap<FsmState>> Method New() End Public #Rem summary: The FSM singleton object. Use GetInstance() to access all FSM functionality. #End Function GetInstance:FSM() If instance = Null Then instance = New FSM() EndIf Return instance End #Rem summary:Executes the specified Finite State Machine. Specifically, this executes the CurrentState of the specified IFSMObject and performs any neccesary transitions via the SetState method. #End Method Execute:Void(obj:IFsmObject) If obj.CurrentState <> Null Local FsmTable:StringMap<FsmState> = StringMap<FsmState>(Self.stateHash.Get(obj)) If FsmTable = Null Then Return EndIf Local targetState:FsmState = GetState(obj, obj.CurrentState().ExecuteState(obj)) SetState(obj, targetState) EndIf End #Rem summary:Attempt To set the CurrentState of the specified IFSMObject To the state specified and call any appropriate state transitions. State is specified by name. #End Method SetState:Void(obj:IFsmObject, stateName:String) If stateName = "" Then Return SetState(obj, GetState(obj, stateName)) End #Rem summary:Attempt To set the CurrentState of the specified IFSMObject To the state specified and call any appropriate state transitions. The actual instance of the desired state is passed. This should normally only be used internally by the FSM class. The preferred method is SetState(IFSMObject obj, string stateName). #End Method SetState:Void(obj:IFsmObject, state:FsmState) Local FsmTable:StringMap<FsmState> = StringMap<FsmState>(Self.stateHash.Get(obj)) If FsmTable = Null Then Return If obj <> Null And state <> Null And FsmTable.Contains(state.StateName()) If obj.CurrentState() <> Null Then obj.CurrentState().ExitState(obj) obj.PreviousState(obj.CurrentState()) obj.CurrentState(state) obj.CurrentState().EnterState(obj) EndIf End #REM summary: Register a state To be accessible To the specified Finite State Machine. This Method will create an instance of the FSMState and hash it under the specified name in a table created specifically for the specified IFSMObject's class type. The state can later be retrieved by name using GetState. #END Method RegisterState:Void(obj:IFsmObject, stateName:String, fsmObject:FsmState) Print("Adding State : " + stateName + " to " + GetClass(obj).Name) If Not Self.stateHash.Contains(obj) Self.stateHash.Add(obj, New StringMap<FsmState>) EndIf Local FsmTable:StringMap<FsmState> = StringMap<FsmState>(Self.stateHash.Get(obj)) If FsmTable = Null ' Throw an exception here !!!! EndIf If FsmTable.Contains(stateName) If FsmTable.Get(stateName) = fsmObject Then Return FsmTable.Remove(stateName) EndIf fsmObject.StateName(stateName) FsmTable.Add(stateName, fsmObject) End #REM summary:Get the instance of the specified state that's registered for the specified IFSMObject. #END Method GetState:FsmState(obj:IFsmObject, stateName:String) Local FsmTable:StringMap<FsmState> = StringMap<FsmState>(Self.stateHash.Get(obj)) If FsmTable = Null Or stateName = "" Return Null EndIf Return FsmState(FsmTable.Get(stateName)) End End |
| ||
Your compare method doesn't meet the documented requirements: "The compare method must return a negative value if lhs < rhs, a positive value if lhs > rhs, or 0 if lhs = rhs. " |
| ||
Hi muddy_shoes thanks for the reply but how do I compare < or > when its an object of type IFsmObject ? |
| ||
You need to add your own ordering value/calculation of some kind. This recent thread discussed the same issue: http://www.monkey-x.com/Community/posts.php?topic=8043 |
| ||
Thanks again ill check that out now. Also when using reflection to see the class name when registering states in RegisterState they all return the same class name monkey.lang.Object. I was expecting the type to be returned. Any ideas why ? Print("Adding State : " + stateName + " to " + GetClass(obj).Name) Adding State : normal to monkey.lang.Object Adding State : alert to monkey.lang.Object Adding State : dead to monkey.lang.Object Adding State : normal to monkey.lang.Object Adding State : alert to monkey.lang.Object Adding State : dead to monkey.lang.Object Adding State : refuel to monkey.lang.Object Adding State : attack to monkey.lang.Object Adding State : gotobase to monkey.lang.Object Adding State : find to monkey.lang.Object Adding State : dead to monkey.lang.Object |
| ||
"Any ideas why?" I haven't used reflection much but I'd guess that you aren't including the appropriate classes under your reflection filter. Maybe check that the classes you're interested in are included with GetClasses? |
| ||
Ill Check the reflection filters, first time i have attempted to use reflection in monkey. Anyway more to the point I added an fsmid:Int and used that in the comparer, works great now. thanks very much for your time :) |