public Program(IInteractionProvider interaction, ITimeProvider time, IStorageProvider storage, ICommandFactory factory) { this.Interaction = interaction; this.Time = time; this.Storage = storage; this.Factory = factory; }
public override sealed async Task RunAsync(IInteractionProvider provider) { OnSubActionStartedOrStopped(0); try { for (int i = 0; !this.count.HasValue || i < this.count.Value; i++) { while (true) { try { provider.EnsureNotCanceled(); OnActionInformationUpdated($"Iteration {i + 1}/{this.count?.ToString() ?? "∞"}"); await this.action.RunAsync(provider); } catch (Exception ex) when(!(ex is SimulatorCanceledException)) { await provider.CheckRetryForExceptionAsync(ex); continue; } break; } } } finally { OnSubActionStartedOrStopped(null); } }
public override sealed async Task RunAsync(IInteractionProvider provider) { provider.PressKey(key); // Use a accurate timer for measuring the time after we need to release the key. await provider.WaitAsync(duration, true); provider.ReleaseKey(key); }
public override sealed async Task RunAsync(IInteractionProvider provider) { OnSubActionStartedOrStopped(0); try { for (int i = 0; !count.HasValue || i < count.Value; i++) { for (;;) { try { provider.EnsureNotCanceled(); OnActionInformationUpdated($"Iteration {i + 1}/{count}"); await action.RunAsync(provider); } catch (Exception ex) when (!(ex is SimulatorCanceledException)) { await provider.CheckRetryForExceptionAsync(ExceptionDispatchInfo.Capture(ex)); continue; } break; } } } finally { OnSubActionStartedOrStopped(null); } }
public override sealed async Task RunAsync(IInteractionProvider provider) { provider.PressKey(this.key); // Use a accurate timer for measuring the time after we need to release the key. await provider.WaitAsync(this.duration, true); provider.ReleaseKey(this.key); }
/// <summary> /// Instantiates the main window and all services. /// By the point this is called, all rendering subsystems have to be defined. /// </summary> public void InitializeApplication() { IGenerationLoader loader = new GenerationLoader(); business = new VisualizerBusiness(loader); interactionProvider = new InteractionProvider(); InteractionRequest.InteractionRequestAdded += InteractionRequest_InteractionRequestAdded; StartupWindow = new MainWindow(new MainWindowViewModel(business)); }
public BootstrapperBase(IInteractionProvider interactionProvider, bool autoconfigureWindow = true) { InteractionRequest.InteractionRequestAdded += (sender, args) => interactionProvider.RegisterInteraction(args.AddedInteraction); // ReSharper disable once PossibleNullReferenceException if (autoconfigureWindow) { // if the code fails here, the set window has no public constructor with no parameters. Consider setting autoconfigureWindow to false window = typeof(TSTartupWindow).GetConstructor(new Type[] { }).Invoke(null) as TSTartupWindow; } }
/// <summary> /// Sends an interaction request to a user /// Отправляет интерактивный запрос пользователю(Вызов модального окна) /// </summary> /// <typeparam name="TViewModel"> /// <see cref="Type" /> that represents the view model of the interaction request /// Тип вью-модели на которую осуществляется переход /// </typeparam> /// <param name="provider"> /// An instance of <see cref="IInteractionProvider{TViewModel}" /> that represents current /// interaction request provider /// Провайдер интерактивного запроса /// </param> /// <param name="onInitialized"> /// An instance of <see cref="Action{T}" /> that represents an initialization callback /// Функция инициализации /// </param> /// <param name="onUninitialized"> /// An instance of <see cref="Action{T}" /> that represents an uninitialization callback /// Функция деинициализации /// </param> /// <returns> /// An instance of <see cref="IInteractionToken" /> that represents interaction request token /// </returns> public IInteractionToken Interact <TViewModel>(IInteractionProvider <TViewModel> provider, Action <TViewModel> onInitialized = null, Action <TViewModel> onUninitialized = null) where TViewModel : IInteractionViewModel { return(Interact(provider, new InteractionInterceptor <TViewModel> { OnAfterInitialization = onInitialized, OnAfterUnInitialization = onUninitialized })); }
protected override sealed async Task FinishThrowFishingRodAsync(IInteractionProvider provider) { // Simply throw the fishing rod straight, without checking for bubbles. Coordinates coords = new Coordinates(800, 1009); var pos = provider.GetCurrentWindowPosition(); coords = pos.RelativeToAbsoluteCoordinates(pos.ScaleCoordinates(coords, MouseHelpers.ReferenceWindowSize)); provider.MoveMouse(coords); await provider.WaitAsync(300); provider.ReleaseMouseButton(); }
public static async Task DoSimpleMouseClickAsync(IInteractionProvider provider, Coordinates coords, VerticalScaleAlignment valign = VerticalScaleAlignment.Center, int buttonDownTimeout = 200) { var pos = provider.GetCurrentWindowPosition(); coords = pos.RelativeToAbsoluteCoordinates(pos.ScaleCoordinates(coords, ReferenceWindowSize, valign)); provider.MoveMouse(coords); provider.PressMouseButton(); await provider.WaitAsync(buttonDownTimeout); provider.ReleaseMouseButton(); }
/// <summary> /// Clicks on the fishing rod button. /// </summary> /// <param name="provider"></param> /// <returns></returns> protected async Task StartThrowFishingRodAsync(IInteractionProvider provider) { Coordinates coords = new Coordinates(800, 846); var pos = provider.GetCurrentWindowPosition(); coords = pos.RelativeToAbsoluteCoordinates(pos.ScaleCoordinates(coords, MouseHelpers.ReferenceWindowSize)); // Move the mouse and press the button. provider.MoveMouse(coords); provider.PressMouseButton(); await provider.WaitAsync(300); }
protected override sealed async Task FinishCastFishingRodAsync(IInteractionProvider provider) { // Simply cast the fishing rod straight, without checking for bubbles. var coords = new Coordinates(800, 1009); var pos = provider.GetCurrentWindowPosition(); coords = pos.ScaleCoordinates(coords, MouseHelpers.ReferenceWindowSize); provider.MoveMouse(coords); await provider.WaitAsync(300); provider.ReleaseMouseButton(); }
public static async Task DoSimpleMouseClickAsync(IInteractionProvider provider, Coordinates coords, VerticalScaleAlignment valign = VerticalScaleAlignment.Center, int buttonDownTimeout = 150) { var pos = provider.GetCurrentWindowPosition(); coords = pos.ScaleCoordinates(coords, ReferenceWindowSize, valign); provider.MoveMouse(coords); provider.PressMouseButton(); await provider.WaitAsync(buttonDownTimeout); provider.ReleaseMouseButton(); }
public override sealed async Task RunAsync(IInteractionProvider provider) { // Click on the Speedchat Icon. Coordinates c = new Coordinates(122, 40); await MouseHelpers.DoSimpleMouseClickAsync(provider, c, VerticalScaleAlignment.Left, 100); int currentYNumber = 0; for (int i = 0; i < menuItems.Length; i++) { await provider.WaitAsync(300); currentYNumber += menuItems[i]; c = new Coordinates(xWidths[i], (40 + currentYNumber * 38)); await MouseHelpers.DoSimpleMouseClickAsync(provider, c, VerticalScaleAlignment.Left, 100); } }
/// <summary> /// Clicks on the fishing rod button. /// </summary> /// <param name="provider"></param> /// <returns></returns> protected async Task StartCastFishingRodAsync(IInteractionProvider provider) { var coords = new Coordinates(800, 846); var pos = provider.GetCurrentWindowPosition(); coords = pos.ScaleCoordinates(coords, MouseHelpers.ReferenceWindowSize); // Move the mouse and press the button. provider.MoveMouse(coords); provider.PressMouseButton(); await provider.WaitAsync(300); CheckForFishErrorDialog(provider); }
public override sealed async Task RunAsync(IInteractionProvider provider) { // Click on the Speedchat Icon. var c = new Coordinates(122, 40); await MouseHelpers.DoSimpleMouseClickAsync(provider, c, VerticalScaleAlignment.Left, 100); int currentYNumber = 0; for (int i = 0; i < this.menuItems.Length; i++) { await provider.WaitAsync(300); currentYNumber += this.menuItems[i]; c = new Coordinates(xWidths[i], (40 + currentYNumber * 38)); await MouseHelpers.DoSimpleMouseClickAsync(provider, c, VerticalScaleAlignment.Left, 100); } }
public PostCommand(IStorageProvider storage, IInteractionProvider interaction, ITimeProvider time, IDictionary <string, string> arguments) { if (storage == null) { throw new ArgumentNullException(nameof(storage)); } this.Storage = storage; if (interaction == null) { throw new ArgumentNullException(nameof(interaction)); } this.Interaction = interaction; if (time == null) { throw new ArgumentNullException(nameof(time)); } this.Time = time; if (arguments == null) { throw new ArgumentNullException(nameof(arguments)); } string user; if (!arguments.TryGetValue("user", out user)) { throw new ArgumentException(Resources.Exception_MissingArgument, nameof(user)); } this.User = user; string message; if (!arguments.TryGetValue("arg", out message)) { throw new ArgumentException(Resources.Exception_MissingArgument, nameof(message)); } this.Message = message; }
/// <summary> /// Sends an interaction request to a user /// Отправляет интерактивный запрос пользователю(Вызов модального окна) /// </summary> /// <typeparam name="TViewModel"> /// <see cref="Type" /> that represents the view model of the interaction request /// </typeparam> /// <param name="provider"> /// An instance of <see cref="IInteractionProvider{TViewModel}" /> that represents current /// interaction request provider /// </param> /// <param name="interactionInterceptor"> /// An instance of <see cref="InteractionInterceptor{TViewModel}" /> to use /// </param> /// <returns> /// An instance of <see cref="IInteractionToken" /> that represents interaction request token /// </returns> public IInteractionToken Interact <TViewModel>(IInteractionProvider <TViewModel> provider, InteractionInterceptor <TViewModel> interactionInterceptor) where TViewModel : IInteractionViewModel { Guard.AgainstNullReference(provider, "provider"); var interactionEvent = this._eventAggregator.GetEvent <InteractionRequestEvent>(); var result = new InteractionToken(interactionEvent); interactionEvent.Publish(new InteractionRequestEventArgs { IsCanceled = false, InteractionProvider = provider, InterceptorsInvoker = new InteractionInterceptorsInvoker <TViewModel>(interactionInterceptor), Callback = result.Dispose }); return(result); }
public override sealed async Task RunAsync(IInteractionProvider provider) { // Click on the "Plant Flower" button. await MouseHelpers.DoSimpleMouseClickAsync(provider, new Coordinates(76, 264), VerticalScaleAlignment.Left); await provider.WaitAsync(200); // Click on the jellybean fields. foreach (int jellybean in jellybeanCombination) { var c = new Coordinates((int)Math.Round(560 + jellybean * 60.5), 514); await MouseHelpers.DoSimpleMouseClickAsync(provider, c, VerticalScaleAlignment.Center, 100); await provider.WaitAsync(100); } await provider.WaitAsync(100); // Click on the "Plant" button. await MouseHelpers.DoSimpleMouseClickAsync(provider, new Coordinates(975, 772)); }
public override sealed async Task RunAsync(IInteractionProvider provider) { // write the text and presses enter. if (!pauseDuration.HasValue) provider.WriteText(text); else { for (int i = 0; i < text.Length; i++) { provider.WriteText(text[i].ToString()); await provider.WaitAsync(pauseDuration.Value); } } // A CR LF (\r\n) in the above string would not have the desired effect; // instead we need to press the enter key. provider.PressKey(AbstractWindowsEnvironment.VirtualKeyShort.Enter); await provider.WaitAsync(100); provider.ReleaseKey(AbstractWindowsEnvironment.VirtualKeyShort.Enter); }
private void CheckForFishErrorDialog(IInteractionProvider provider) { // Check if a dialog appeared, which means we don't have any more jelly beans or // the fish bucket is full. var screenshot = provider.GetCurrentWindowScreenshot(); bool foundDialog = true; foreach (var point in fishErrorDialogCoordinates) { if (!CompareColor(fishDialogColor, screenshot.GetPixel( screenshot.WindowPosition.ScaleCoordinates(point, MouseHelpers.ReferenceWindowSize)), 4)) { foundDialog = false; break; } } if (foundDialog) { throw new InvalidOperationException( "Either your fish bucket is full or you don't have any more jellybeans for bait."); } }
public override sealed async Task RunAsync(IInteractionProvider provider) { // Click on the "Plant Flower" button. await MouseHelpers.DoSimpleMouseClickAsync(provider, new Coordinates(76, 264), VerticalScaleAlignment.Left); await provider.WaitAsync(200); // Click on the jellybean fields. foreach (int jellybean in this.jellybeanCombination) { var c = new Coordinates((int)Math.Round(560 + jellybean * 60.5), 514); await MouseHelpers.DoSimpleMouseClickAsync(provider, c, VerticalScaleAlignment.Center, 100); await provider.WaitAsync(100); } await provider.WaitAsync(100); // Click on the "Plant" button. await MouseHelpers.DoSimpleMouseClickAsync(provider, new Coordinates(975, 772)); }
public override sealed async Task RunAsync(IInteractionProvider provider) { // Cast the fishing rod OnActionInformationUpdated("Casting…"); await StartCastFishingRodAsync(provider); await FinishCastFishingRodAsync(provider); // Then, wait until we find a window displaying the caught fish // or the specified number of seconds has passed. OnActionInformationUpdated("Waiting for the fish result dialog…"); var sw = new Stopwatch(); sw.Start(); bool found = false; while (!found && sw.ElapsedMilliseconds <= this.WaitingForFishResultDialogTime) { await provider.WaitAsync(500); // Get a current screenshot. var screenshot = provider.GetCurrentWindowScreenshot(); foreach (var c in fishResultDialogCoordinates) { var cc = screenshot.WindowPosition.ScaleCoordinates( c, MouseHelpers.ReferenceWindowSize); var col = screenshot.GetPixel(cc); if (CompareColor(fishDialogColor, col, 10)) { // OK, we caught a fish, so break from the loop. found = true; break; } } } }
public override sealed async Task RunAsync(IInteractionProvider provider) { // write the text and presses enter. if (!this.pauseDuration.HasValue) { provider.WriteText(this.text); } else { for (int i = 0; i < this.text.Length; i++) { provider.WriteText(this.text[i].ToString()); await provider.WaitAsync(this.pauseDuration.Value); } } // A CR LF (\r\n) in the above string would not have the desired effect; // instead we need to press the enter key. provider.PressKey(AbstractWindowsEnvironment.VirtualKeyShort.Enter); await provider.WaitAsync(100); provider.ReleaseKey(AbstractWindowsEnvironment.VirtualKeyShort.Enter); }
public FollowCommand(IStorageProvider storage, IInteractionProvider interaction, IDictionary <string, string> arguments) { if (storage == null) { throw new ArgumentNullException(nameof(storage)); } this.Storage = storage; if (interaction == null) { throw new ArgumentNullException(nameof(interaction)); } this.Interaction = interaction; if (arguments == null) { throw new ArgumentNullException(nameof(arguments)); } string user; if (!arguments.TryGetValue("user", out user)) { throw new ArgumentException(Resources.Exception_MissingArgument, nameof(user)); } this.User = user; string userToFollow; if (!arguments.TryGetValue("arg", out userToFollow)) { throw new ArgumentException(Resources.Exception_MissingArgument, nameof(userToFollow)); } this.UserToFollow = userToFollow; }
public override sealed async Task RunAsync(IInteractionProvider provider) { // Cast the fishing rod OnActionInformationUpdated("Casting…"); await StartCastFishingRodAsync(provider); await FinishCastFishingRodAsync(provider); // Then, wait until we find a window displaying the caught fish // or the specified number of seconds has passed. OnActionInformationUpdated("Waiting for the fish result dialog…"); Stopwatch sw = new Stopwatch(); sw.Start(); bool found = false; while (!found && sw.ElapsedMilliseconds <= WaitingForFishResultDialogTime) { await provider.WaitAsync(500); // Get a current screenshot. var screenshot = provider.GetCurrentWindowScreenshot(); foreach (Coordinates c in fishResultDialogCoordinates) { var cc = screenshot.WindowPosition.ScaleCoordinates( c, MouseHelpers.ReferenceWindowSize); var col = screenshot.GetPixel(cc); if (CompareColor(fishDialogColor, col, 10)) { // OK, we caught a fish, so break from the loop. found = true; break; } } } }
public abstract Task RunAsync(IInteractionProvider provider);
public override sealed async Task RunAsync(IInteractionProvider provider) { // Run the actions. int currentIdx = -1; var randomOrder = null as int[]; Func <int> getNextActionIndex; if (this.type == CompoundActionType.Sequential) { getNextActionIndex = () => (!this.loop && currentIdx + 1 == this.actionList.Count) ? -1 : currentIdx = (currentIdx + 1) % this.actionList.Count; } else if (this.type == CompoundActionType.RandomIndex) { getNextActionIndex = () => this.rng.Next(this.actionList.Count); } else { randomOrder = new int[this.actionList.Count]; getNextActionIndex = () => { if (!this.loop && currentIdx + 1 == this.actionList.Count) { return(-1); } currentIdx = (currentIdx + 1) % this.actionList.Count; if (currentIdx == 0) { // Generate a new order array. for (int i = 0; i < randomOrder.Length; i++) { randomOrder[i] = i; } for (int i = 0; i < randomOrder.Length; i++) { int rIdx = this.rng.Next(randomOrder.Length - i); int tmp = randomOrder[i]; randomOrder[i] = randomOrder[i + rIdx]; randomOrder[i + rIdx] = tmp; } } return(randomOrder[currentIdx]); }; } while (true) { int nextIdx = getNextActionIndex(); if (nextIdx == -1) { break; } OnActionInformationUpdated($"Running action {nextIdx + 1}"); while (true) { try { // Check if the simulator has already been canceled. provider.EnsureNotCanceled(); OnSubActionStartedOrStopped(nextIdx); try { await this.actionList[nextIdx].RunAsync(provider); } finally { OnSubActionStartedOrStopped(null); } // After running an action, wait. int waitInterval = this.rng.Next(this.minimumPauseDuration, this.maximumPauseDuration); OnActionInformationUpdated($"Pausing {waitInterval} ms"); await provider.WaitAsync(waitInterval); } catch (Exception ex) when(!(ex is SimulatorCanceledException)) { await provider.CheckRetryForExceptionAsync(ex); continue; } break; } } }
/// <summary> /// Detects a fish bubble and then casts the fishing rod by moving the mouse to the /// desired position and releaseing the mouse button. /// </summary> /// <param name="provider"></param> /// <returns></returns> protected abstract Task FinishCastFishingRodAsync(IInteractionProvider provider);
public override sealed async Task RunAsync(IInteractionProvider provider) => await provider.WaitAsync(duration);
protected override sealed async Task FinishCastFishingRodAsync(IInteractionProvider provider) { // Try to find a bubble. const string actionInformationScanning = "Scanning for fish bubbles…"; OnActionInformationUpdated(actionInformationScanning); const int scanStep = 15; Stopwatch sw = new Stopwatch(); sw.Start(); Coordinates? oldCoords = null; Coordinates? newCoords; int coordsMatchCounter = 0; while (true) { var screenshot = provider.GetCurrentWindowScreenshot(); newCoords = null; // TODO: The fish bubble detection should be changed so that it does not scan // for a specific color, but instead checks that for a point if the color is // darker than the neighbor pixels (in some distance). for (int y = spotData.Scan1.Y; y <= spotData.Scan2.Y && !newCoords.HasValue; y += scanStep) { for (int x = spotData.Scan1.X; x <= spotData.Scan2.X; x += scanStep) { var c = new Coordinates(x, y); c = screenshot.WindowPosition.ScaleCoordinates(c, MouseHelpers.ReferenceWindowSize); if (CompareColor(spotData.BubbleColor, screenshot.GetPixel(c), spotData.Tolerance)) { newCoords = new Coordinates(x + 20, y + 20); Coordinates scaledCoords = screenshot.WindowPosition.RelativeToAbsoluteCoordinates( screenshot.WindowPosition.ScaleCoordinates( newCoords.Value, MouseHelpers.ReferenceWindowSize)); OnActionInformationUpdated($"Found bubble at {scaledCoords.X}, {scaledCoords.Y}…"); break; } } } if (!newCoords.HasValue) OnActionInformationUpdated(actionInformationScanning); if (newCoords.HasValue && oldCoords.HasValue && Math.Abs(oldCoords.Value.X - newCoords.Value.X) <= scanStep && Math.Abs(oldCoords.Value.Y - newCoords.Value.Y) <= scanStep) { // The new coordinates are (nearly) the same as the previous ones. coordsMatchCounter++; } else { // Reset the counter and update the coordinates even if we currently didn't // find them. oldCoords = newCoords; coordsMatchCounter = 0; } // Now position the mouse already so that we just need to release the button. if (!newCoords.HasValue) { // If we couldn't find the bubble we use default destination x,y values. newCoords = new Coordinates(800, 1009); } else { // Calculate the destination coordinates. newCoords = new Coordinates( (int)Math.Round(800d + 120d / 429d * (800d - newCoords.Value.X) * (0.75 + (820d - newCoords.Value.Y) / 820 * 0.38)), (int)Math.Round(846d + 169d / 428d * (820d - newCoords.Value.Y)) ); } // Note: Instead of using a center position for scaling the X coordinate, // TTR seems to interpret it as being scaled from an 4/3 ratio. Therefore // we need to specify "NoAspectRatio" here. // However it could be that they will change this in the future, then // we would need to use "Center". // Note: We assume the point to click on is exactly centered. Otherwise // we would need to adjust the X coordinate accordingly. var coords = screenshot.WindowPosition.RelativeToAbsoluteCoordinates( screenshot.WindowPosition.ScaleCoordinates(newCoords.Value, MouseHelpers.ReferenceWindowSize, VerticalScaleAlignment.NoAspectRatio)); provider.MoveMouse(coords); if (coordsMatchCounter == 2) { // If we found the same coordinates two times, we assume // the bubble is not moving at the moment. break; } await provider.WaitAsync(500); // Ensure we don't wait longer than 36 seconds. if (sw.ElapsedMilliseconds >= 36000) break; } // There is no need to wait here because the mouse has already been positioned and we // waited at least 2x 500 ms at the new position, so now just release the mouse button. provider.ReleaseMouseButton(); }
public override async Task RunAsync(IInteractionProvider provider) { var c = new Coordinates(1397, 206 + (int)this.button * 49); await MouseHelpers.DoSimpleMouseClickAsync(provider, c, VerticalScaleAlignment.Right); }
public override async Task RunAsync(IInteractionProvider provider) { Coordinates c = new Coordinates(1397, 206 + (int)button * 49); await MouseHelpers.DoSimpleMouseClickAsync(provider, c, VerticalScaleAlignment.Right); }
public override sealed async Task RunAsync(IInteractionProvider provider) { var c = new Coordinates(1503, 1086); await MouseHelpers.DoSimpleMouseClickAsync(provider, c); }
public override sealed async Task RunAsync(IInteractionProvider provider) { // Run the actions. int currentIdx = -1; int[] randomOrder = null; Func<int> getNextActionIndex; if (type == CompoundActionType.Sequential) getNextActionIndex = () => (!loop && currentIdx + 1 == actionList.Count) ? -1 : currentIdx = (currentIdx + 1) % actionList.Count; else if (type == CompoundActionType.RandomIndex) getNextActionIndex = () => rng.Next(actionList.Count); else { randomOrder = new int[actionList.Count]; getNextActionIndex = () => { if (!loop && currentIdx + 1 == actionList.Count) return -1; currentIdx = (currentIdx + 1) % actionList.Count; if (currentIdx == 0) { // Generate a new order array. for (int i = 0; i < randomOrder.Length; i++) randomOrder[i] = i; for (int i = 0; i < randomOrder.Length; i++) { int rIdx = rng.Next(randomOrder.Length - i); int tmp = randomOrder[i]; randomOrder[i] = randomOrder[i + rIdx]; randomOrder[i + rIdx] = tmp; } } return randomOrder[currentIdx]; }; } while (true) { // Check if the simulator has already been canceled. provider.EnsureNotCanceled(); int nextIdx = getNextActionIndex(); if (nextIdx == -1) break; OnActionInformationUpdated($"Running action {nextIdx + 1}"); OnSubActionStartedOrStopped(nextIdx); try { IAction action = actionList[nextIdx]; await action.RunAsync(provider); } finally { OnSubActionStartedOrStopped(null); } // After running an action, wait. int waitInterval = rng.Next(minimumPauseDuration, maximumPauseDuration); OnActionInformationUpdated($"Pausing {waitInterval} ms"); await provider.WaitAsync(waitInterval); } }
public static void Initialize(IInteractionProvider provider) { provider.NewInteraction += newInteraction; _timer = new System.Threading.Timer(timerTick, null, Timeout.Infinite, Timeout.Infinite); }
public override sealed async Task RunAsync(IInteractionProvider provider) => await provider.WaitAsync(this.duration);
protected override sealed async Task FinishCastFishingRodAsync(IInteractionProvider provider) { // Try to find a bubble. const string actionInformationScanning = "Scanning for fish bubbles…"; OnActionInformationUpdated(actionInformationScanning); const int scanStep = 15; var sw = new Stopwatch(); sw.Start(); Coordinates?oldCoords = null; Coordinates?newCoords; int coordsMatchCounter = 0; while (true) { var screenshot = provider.GetCurrentWindowScreenshot(); newCoords = null; // TODO: The fish bubble detection should be changed so that it does not scan // for a specific color, but instead checks that for a point if the color is // darker than the neighbor pixels (in some distance). for (int y = this.spotData.Scan1.Y; y <= this.spotData.Scan2.Y && !newCoords.HasValue; y += scanStep) { for (int x = this.spotData.Scan1.X; x <= this.spotData.Scan2.X; x += scanStep) { var c = new Coordinates(x, y); c = screenshot.WindowPosition.ScaleCoordinates(c, MouseHelpers.ReferenceWindowSize); if (CompareColor(this.spotData.BubbleColor, screenshot.GetPixel(c), this.spotData.Tolerance)) { newCoords = new Coordinates(x + 20, y + 20); var scaledCoords = screenshot.WindowPosition.ScaleCoordinates( newCoords.Value, MouseHelpers.ReferenceWindowSize); OnActionInformationUpdated($"Found bubble at {scaledCoords.X}, {scaledCoords.Y}…"); break; } } } if (!newCoords.HasValue) { OnActionInformationUpdated(actionInformationScanning); } if (newCoords.HasValue && oldCoords.HasValue && Math.Abs(oldCoords.Value.X - newCoords.Value.X) <= scanStep && Math.Abs(oldCoords.Value.Y - newCoords.Value.Y) <= scanStep) { // The new coordinates are (nearly) the same as the previous ones. coordsMatchCounter++; } else { // Reset the counter and update the coordinates even if we currently didn't // find them. oldCoords = newCoords; coordsMatchCounter = 0; } // Now position the mouse already so that we just need to release the button. if (!newCoords.HasValue) { // If we couldn't find the bubble we use default destination x,y values. newCoords = new Coordinates(800, 1009); } else { // Calculate the destination coordinates. newCoords = new Coordinates( (int)Math.Round(800d + 120d / 429d * (800d - newCoords.Value.X) * (0.75 + (820d - newCoords.Value.Y) / 820 * 0.38)), (int)Math.Round(846d + 169d / 428d * (820d - newCoords.Value.Y)) ); } // Note: Instead of using a center position for scaling the X coordinate, // TTR seems to interpret it as being scaled from an 4/3 ratio. Therefore // we need to specify "NoAspectRatio" here. // However it could be that they will change this in the future, then // we would need to use "Center". // Note: We assume the point to click on is exactly centered. Otherwise // we would need to adjust the X coordinate accordingly. var coords = screenshot.WindowPosition.ScaleCoordinates(newCoords.Value, MouseHelpers.ReferenceWindowSize, VerticalScaleAlignment.NoAspectRatio); provider.MoveMouse(coords); if (coordsMatchCounter == 2) { // If we found the same coordinates two times, we assume // the bubble is not moving at the moment. break; } await provider.WaitAsync(500); // Ensure we don't wait longer than 36 seconds. if (sw.ElapsedMilliseconds >= 36000) { break; } } // There is no need to wait here because the mouse has already been positioned and we // waited at least 2x 500 ms at the new position, so now just release the mouse button. provider.ReleaseMouseButton(); }
public override sealed async Task RunAsync(IInteractionProvider provider) { Coordinates c = new Coordinates(1503, 1086); await MouseHelpers.DoSimpleMouseClickAsync(provider, c); }
public ExitCommand(IInteractionProvider interaction) { this.Interaction = interaction; }
public UnknownCommand(IInteractionProvider interaction) { this.Interaction = interaction; }