1 /** 2 * Represents a state for an EntityStateMachine. The state contains any number of ComponentProviders which 3 * are used to add components to the entity when this state is entered. 4 */ 5 module ashd.fsm.entityState; 6 7 import std.conv: to; 8 9 10 import ashd.core.component : Component; 11 import ashd.fsm.componentInstanceProvider : ComponentInstanceProvider; 12 import ashd.fsm.componentSingletonProvider: ComponentSingletonProvider; 13 import ashd.fsm.componentTypeProvider : ComponentTypeProvider; 14 import ashd.fsm.dynamicComponentProvider : DynamicComponentProvider; 15 import ashd.fsm.IComponentProvider : IComponentProvider; 16 17 18 /// 19 public class EntityState 20 { 21 private 22 { 23 IComponentProvider[ClassInfo] mProviders; 24 } 25 26 27 @property IComponentProvider[ClassInfo] providers() { return mProviders; }; 28 29 /** 30 * Add a new ComponentMapping to this state. The mapping is a utility class that is used to 31 * map a component type to the provider that provides the component. 32 * 33 * @param type The type of component to be mapped 34 * @return The component mapping to use when setting the provider for the component 35 */ 36 public StateComponentMapping add( ClassInfo class_a ) 37 { 38 return new StateComponentMapping( this, class_a ); 39 } 40 41 /** 42 * Get the ComponentProvider for a particular component type. 43 * 44 * @param type The type of component to get the provider for 45 * @return The ComponentProvider 46 */ 47 public IComponentProvider get( ClassInfo class_a ) 48 { 49 if ( class_a in mProviders ) 50 return mProviders[ class_a ]; 51 else 52 return null; 53 } 54 55 56 /** 57 * To determine whether this state has a provider for a specific component type. 58 * 59 * @param type The type of component to look for a provider for 60 * @return true if there is a provider for the given type, false otherwise 61 */ 62 public bool has( ClassInfo class_a ) 63 { 64 return ( class_a in mProviders) != null; 65 } 66 67 } 68 69 70 /** 71 * Used by the EntityState class to create the mappings of components to providers via a fluent interface. 72 */ 73 private class StateComponentMapping 74 { 75 private 76 { 77 EntityState mCreatingState; 78 IComponentProvider mProvider; 79 ClassInfo mComponentType; 80 } 81 82 /** 83 * Used internally, the constructor creates a component mapping. The constructor 84 * creates a ComponentTypeProvider as the default mapping, which will be replaced 85 * by more specific mappings if other methods are called. 86 * 87 * @param creatingState The EntityState that the mapping will belong to 88 * @param type The component type for the mapping 89 */ 90 public this( EntityState creatingState_a, ClassInfo class_a ) 91 { 92 mCreatingState = creatingState_a; 93 mComponentType = class_a; 94 this.withType( class_a ); 95 } 96 97 /** 98 * Creates a mapping for the component type to a specific component instance. A 99 * ComponentInstanceProvider is used for the mapping. 100 * 101 * @param component The component instance to use for the mapping 102 * @return This ComponentMapping, so more modifications can be applied 103 */ 104 public StateComponentMapping withInstance(T)( T component_a ) 105 { 106 setProvider( new ComponentInstanceProvider!T( component_a ), T.classinfo ); 107 return this; 108 } 109 110 /** 111 * Creates a mapping for the component type to new instances of the provided type. 112 * The type should be the same as or extend the type for this mapping. A ComponentTypeProvider 113 * is used for the mapping. 114 * 115 * @param type The type of components to be created by this mapping 116 * @return This ComponentMapping, so more modifications can be applied 117 */ 118 public StateComponentMapping withType( ClassInfo type_a ) 119 { 120 setProvider( new ComponentTypeProvider( type_a ), type_a ); 121 return this; 122 } 123 124 /** 125 * Creates a mapping for the component type to a single instance of the provided type. 126 * The instance is not created until it is first requested. The type should be the same 127 * as or extend the type for this mapping. A ComponentSingletonProvider is used for 128 * the mapping. 129 * 130 * @param The type of the single instance to be created. If omitted, the type of the 131 * mapping is used. 132 * @return This ComponentMapping, so more modifications can be applied 133 */ 134 public StateComponentMapping withSingleton( ClassInfo type_a = null ) 135 { 136 if ( !type_a ) 137 { 138 type_a = mComponentType; 139 } 140 setProvider( new ComponentSingletonProvider( type_a ), type_a ); 141 return this; 142 } 143 144 /** 145 * Creates a mapping for the component type to a method call. A 146 * DynamicComponentProvider is used for the mapping. 147 * 148 * @param method The method to return the component instance 149 * @return This ComponentMapping, so more modifications can be applied 150 */ 151 public StateComponentMapping withMethod(T)( T delegate() method_a ) 152 { 153 setProvider( new DynamicComponentProvider!T( method_a ), T.classinfo ); 154 return this; 155 } 156 157 /** 158 * Creates a mapping for the component type to any ComponentProvider. 159 * 160 * @param provider The component provider to use. 161 * @return This ComponentMapping, so more modifications can be applied. 162 */ 163 public StateComponentMapping withProvider( IComponentProvider provider_a, ClassInfo class_a ) 164 { 165 setProvider( provider_a, class_a ); 166 return this; 167 } 168 169 /** 170 * Maps through to the add method of the EntityState that this mapping belongs to 171 * so that a fluent interface can be used when configuring entity states. 172 * 173 * @param type The type of component to add a mapping to the state for 174 * @return The new ComponentMapping for that type 175 */ 176 public StateComponentMapping add( ClassInfo class_a ) 177 { 178 return mCreatingState.add( class_a ); 179 } 180 181 private void setProvider( IComponentProvider provider_a, ClassInfo class_a ) 182 { 183 mProvider = provider_a; 184 185 mCreatingState.mProviders[ class_a ] = provider_a; 186 } 187 } 188