/// <summary> /// Create a coordinator which will handle the interaction logic /// </summary> /// <param name="processor">Should almost always be "this" - the component using this coordinator should /// implement IInteractionProcessor and delegate processing to this coordinator. /// Component which will process the interaction on the server side.</param> /// <param name="willInteract">Can be null. If specified, invoked client side to determine if request /// should be sent to server. Invoked server side to see if interaction logic should be invoked.</param> /// <param name="interactionLogic">Function to invoke on the server side to perform the interaction logic /// if validation succeeds.</param> public InteractionCoordinator(IInteractionProcessor <T> processor, Func <T, NetworkSide, bool> willInteract, Action <T> interactionLogic) { this.processor = processor; this.interactionLogic = interactionLogic; this.willInteract = willInteract; }
/// <summary> /// Create a coordinator which will handle the interaction logic /// </summary> /// <param name="processor">Should almost always be "this" - the component using this coordinator should /// implement IInteractionProcessor and delegate processing to this coordinator. /// Component which will process the interaction on the server side.</param> /// <param name="validations">Validations to perform on client and server side. If any validation fails, /// the entire validation will fail.</param> /// <param name="interactionLogic">Function to invoke on the server side to perform the interaction logic /// if validation succeeds.</param> public InteractionCoordinator(IInteractionProcessor <T> processor, IList <IInteractionValidator <T> > validations, Func <T, InteractionResult> interactionLogic) { this.validations = validations; this.processor = processor; this.interactionLogic = interactionLogic; }
/// <summary> /// Send a request to the server to validate + perform the interaction. /// </summary> /// <param name="info">info on the interaction being performed. Each object involved in the interaction /// must have a networkidentity.</param> /// <param name="processor">component which will process the interaction on the server-side. The processor's /// info and result types must match the info and result type of one of the interaction type constants /// defined in InteractionType. /// /// This component /// must live on a GameObject with a network identity, and there must only be one instance of this component /// on the object. For organization, we suggest that the component which is sending this message /// should be the processor, as such this parameter should almost always be passed using the "this" keyword, and /// should almost always be either a component on the target object or a component on the used object</param> /// <typeparamref name="T">Interaction subtype /// for the interaction that the processor can handle (such as MouseDrop for a mouse drop interaction). /// Must be a subtype of Interaction.</typeparamref> public static void SendRequest <T>(T info, IInteractionProcessor <T> processor) where T : Interaction { if (!info.Performer.Equals(PlayerManager.LocalPlayer)) { Logger.LogError("Client attempting to perform an interaction on behalf of another player." + " This is not allowed. Client can only perform an interaction as themselves. Message" + " will not be sent.", Category.NetMessage); return; } if (!(processor is Component)) { Logger.LogError("processor must be a component, but isn't. The message will not be sent.", Category.NetMessage); return; } //send the message appropriate to the specific interaction type var processorObject = (processor as Component).gameObject; if (typeof(T) == typeof(PositionalHandApply)) { RequestPositionalHandApplyMessage.Send(info as PositionalHandApply, processorObject); return; } else if (typeof(T) == typeof(HandApply)) { RequestHandApplyMessage.Send(info as HandApply, processorObject); return; } else if (typeof(T) == typeof(AimApply)) { RequestAimApplyMessage.Send(info as AimApply, processorObject); return; } else if (typeof(T) == typeof(MouseDrop)) { RequestMouseDropMessage.Send(info as MouseDrop, processorObject); return; } else if (typeof(T) == typeof(HandActivate)) { RequestHandActivateMessage.Send(info as HandActivate, processorObject); return; } else if (typeof(T) == typeof(InventoryApply)) { RequestInventoryApplyMessage.Send(info as InventoryApply, processorObject); return; } //TODO: Other types //we didn't send anything Logger.LogErrorFormat("Interaction type was {0} - we couldn't determine what to do for this interaction" + " type, most likely because it hasn't been implemented yet." + " Please implement handling for this interaction type in InteractionMessageUtils.SendRequest()", Category.NetMessage, nameof(T)); }
/// <summary> /// Create a coordinator which will handle the interaction logic. It is recommended to use the /// other constructor so you can use the re-usable IInteractionValidators and avoid code duplication. /// </summary> /// <param name="processor">Should almost always be "this" - the component using this coordinator should /// implement IInteractionProcessor and delegate processing to this coordinator. /// Component which will process the interaction on the server side.</param> /// <param name="validationLogic">function which will validate the interaction on client and server side.</param> /// <param name="interactionLogic">Function to invoke on the server side to perform the interaction logic /// if validation succeeds.</param> public InteractionCoordinator(IInteractionProcessor <T> processor, Func <T, NetworkSide, ValidationResult> validationLogic, Func <T, InteractionResult> interactionLogic) { this.validations = new List <IInteractionValidator <T> > { new FunctionValidator <T>(validationLogic) }; this.processor = processor; this.interactionLogic = interactionLogic; }
/// <summary> /// Send a request to the server to validate + perform the interaction. /// </summary> /// <param name="info">info on the interaction being performed. Each object involved in the interaction /// must have a networkidentity.</param> /// <param name="processor">component which will process the interaction on the server-side. The processor's /// info and result types must match the info and result type of one of the interaction type constants /// defined in InteractionType. /// /// This component /// must live on a GameObject with a network identity, and there must only be one instance of this component /// on the object. For organization, we suggest that the component which is sending this message /// should be the processor, as such this parameter should almost always be passed using the "this" keyword, and /// should almost always be either a component on the target object or a component on the used object</param> /// <typeparamref name="T">Interaction subtype /// for the interaction that the processor can handle (such as MouseDrop for a mouse drop interaction). /// Must be a subtype of Interaction.</typeparamref> /// <returns></returns> public static RequestInteractMessage Send <T>(T info, IInteractionProcessor <T> processor) where T : Interaction { if (!info.Performer.Equals(PlayerManager.LocalPlayer)) { Logger.LogError("Client attempting to perform an interaction on behalf of another player." + " This is not allowed. Client can only perform an interaction as themselves. Message" + " will not be sent.", Category.NetMessage); return(null); } if (!(processor is Component)) { Logger.LogError("processor must be a component, but isn't. The message will not be sent.", Category.NetMessage); return(null); } short typeID; var processorObject = (processor as Component).gameObject; if (InteractionTypeToID.TryGetValue(typeof(T), out typeID)) { RequestInteractMessage msg = null; //send the message appropriate to the specific interaction type if (typeof(T) == typeof(MouseDrop)) { msg = CreateMouseDropMessage(info as MouseDrop, processorObject, typeID); } else if (typeof(T) == typeof(HandApply)) { msg = CreateHandApplyMessage(info as HandApply, processorObject, typeID); } //TODO: Other types if (msg != null) { msg.Send(); return(msg); } else { Logger.LogErrorFormat("Interaction type was {0} - we couldn't determine what to do for this interaction" + " type, most likely because it hasn't been implemented yet." + " Please implement handling for this interaction type in RequestInteractMessage.Send()", Category.NetMessage, nameof(T)); return(null); } } else { Logger.LogError("Interaction's concrete type could not be mapped to an ID, this is most likely" + " a programming error. Message will not be sent", Category.NetMessage); return(null); } }