/// <summary> /// Update mod state. Try to keep processing quick here. /// </summary> public void OnUpdate() { if (!(Game1.player.CurrentTool is FishingRod)) { return; } FishingRod currentTool = Game1.player.CurrentTool as FishingRod; // Could set up a state machine to track this, but for now just check either in the minigame or not. if (Game1.activeClickableMenu is BobberBar && currentTool.isFishing) { PlayFishMinigame(); } else { // Do everything else the mod does outside of the fishing game. // If this is the first time out of the fishing game, clear the data. if (this.inFishingMenu) { log.Silly("Left Fishing minigame, clearing memory"); this.UnloadSVReflectionObjects(); this.inFishingMenu = false; IsButtonDownHack.simulateDown = false; } // This might be where a state machine might help, as an extra check, (e.g can't set power if you're not done casting, etc...) // but the SV tool API seems to give us enough data to have a go at it just checking conditionals. // Sequential steps to automate fishing if (config.autoCast && ShouldDoAutoCast(currentTool)) { log.Trace("Attempting to cast for the user"); currentTool.beginUsing(Game1.currentLocation, Game1.player.getStandingX(), Game1.player.getStandingY(), Game1.player); } if (config.maxCastPower && ShouldSetCastingPower(currentTool)) { log.Trace("Modifying cast to max cast power"); // Apparently for max to be registered it needs to be > 1.0, but anything over increases the // power bar past the UI, so make it a small number. Also, 1.001F is too small. currentTool.castingPower = 1.01F; } if (config.quickHook && ShouldSetQuickHook(currentTool)) { log.Trace("Modifying cast so fish will bite quickly."); // Game uses fishingBiteAccumulator as the value that gets modified so we should only modify that one // and let the game increase it and handle logic as they become equal. Change the gap if it doesn't // generate a quick hit quick enough. currentTool.fishingBiteAccumulator = currentTool.timeUntilFishingBite - fishingBiteAccumulatorGap; } if (config.autoHook && ShouldDoAutoHook(currentTool)) { log.Trace("Executing hook function for FishingRod"); currentTool.DoFunction(Game1.currentLocation, Game1.player.getStandingX(), Game1.player.getStandingY(), (int)currentTool.castingPower, Game1.player); } // Click away the catched fish. The conditionals are ordered here in a way // the check for the popup happens before the config check so the code can // always check the treasure chest. See the variable doneCaughtFish for more // info. if (ShouldDoDismissCaughtPopup(currentTool)) { log.Trace("Tool is sitting at caught fish popup"); doneCaughtFish = true; if (config.autoFinish && config.HarmonyLoad) { log.Trace("Closing popup with Harmony"); ClickAtAllHack.simulateClick = true; } } else { if (ClickAtAllHack.simulateClick) { log.Trace("Turning off Harmony injection for caught fish popup"); ClickAtAllHack.simulateClick = false; } } // Deal with any treasure that has popped up if (ShouldDoProcessTreasure(currentTool) && doneCaughtFish) { log.Trace("Found treasure after the caught fish popup"); doneCaughtFish = false; if (config.autoFinish) { log.Trace("Acquiring treasure"); ItemGrabMenu m = Game1.activeClickableMenu as ItemGrabMenu; if (m.ItemsToGrabMenu != null && m.ItemsToGrabMenu.actualInventory != null) { if (AcquireTreasure(m.ItemsToGrabMenu.actualInventory)) { m.exitThisMenu(true); } else { HandleItemGrabMenuError(m, "might be full inventory"); } } else { HandleItemGrabMenuError(m, "treasure chest is open, but inventory is null"); } } } } }
private void OnUpdateTicked(object sender, UpdateTickedEventArgs args) { Farmer player = Game1.player; // freeze time Game1.gameTimeInterval = 0; // infinite stamina player.stamina = player.MaxStamina; if (player == null || !player.IsLocalPlayer) { return; } if (!(Game1.player.CurrentTool is FishingRod)) { return; } FishingRod rod = Game1.player.CurrentTool as FishingRod; if (autoCastRod & ShouldDoAutoCast(rod)) { rod.beginUsing(Game1.currentLocation, Game1.player.getStandingX(), Game1.player.getStandingY(), Game1.player); } if (rod.isTimingCast) { rod.castingTimerSpeed = 0; rod.castingPower = 1; } if (!rod.isNibbling && rod.isFishing && !rod.isReeling && !rod.pullingOutOfWater && !rod.hit) { rod.timeUntilFishingBite = 0; } if (rod.isNibbling && rod.isFishing && !rod.isReeling && !rod.pullingOutOfWater && !rod.hit) { Farmer.useTool(player); } // Click away the catched fish. The conditionals are ordered here in a way // the check for the popup happens before the config check so the code can // always check the treasure chest. See the variable doneCaughtFish for more // info. if (ShouldDoDismissCaughtPopup(rod)) { log.Trace("Tool is sitting at caught fish popup"); log.Trace("Closing popup with Harmony"); ClickAtAllHack.simulateClick = true; } // 6x per second if (args.IsMultipleOf(10)) { IsButtonDownHack.simulateDown = false; if (Game1.activeClickableMenu is BobberBar bar) { int best_action; double diffBobberFish = bobberPosition - bobberBarPos; double[] OldState = new double[] { (double)bobberBarPos, (double)bobberPosition, (double)bobberBarSpeed, (double)distanceFromCatching }; // if is the first iteration StateBuffer don't have anything if (CountFishes == 0) { StateBuffer = OldState; } // Update State bobberBarPos = Helper.Reflection.GetField <float>(bar, "bobberBarPos").GetValue(); bobberBarSpeed = Helper.Reflection.GetField <float>(bar, "bobberBarSpeed").GetValue(); bobberPosition = Helper.Reflection.GetField <float>(bar, "bobberPosition").GetValue(); distanceFromCatching = Helper.Reflection.GetField <float>(bar, "distanceFromCatching").GetValue(); diffBobberFish = bobberPosition - bobberBarPos; double [] NewState = new double[] { (double)bobberBarPos, (double)bobberPosition, (double)bobberBarSpeed, (double)distanceFromCatching }; int rand = rnd.Next(100); best_action = (int)Agent.Update(StateBuffer, OldState, NewState); if (rand < 5) { rand = 0; // explore random action and it's outcome //best_action = rnd.Next(1); } // execute action if needed if (best_action == 1) { IsButtonDownHack.simulateDown = true; } else { // do NOTHING //IsButtonDownHack.simulateDown = false; } // store last state StateBuffer = OldState; } } }