using BehaviourTree;
using BetterGenshinImpact.GameTask.AutoFishing;
using BetterGenshinImpact.GameTask.Model.Area.Converter;
using BetterGenshinImpact.GameTask.Model.Area;
using Microsoft.Extensions.Time.Testing;
using OpenCvSharp;
using BehaviourTree.Composites;
using BehaviourTree.FluentBuilder;
namespace BetterGenshinImpact.UnitTest.GameTaskTests.AutoFishingTests
{
public partial class BehavioursTests
{
[Theory]
[InlineData(@"20250225101304534_ThrowRod_Succeeded.png", "false worm bait")]
[InlineData(@"20250226162217468_ThrowRod_Succeeded.png", "fruit paste bait")]
///
/// 测试各种抛竿,结果为成功
///
public void ThrowRodTest_VariousFish_ShouldSuccess(string screenshot1080p, string selectedBaitName)
{
//
Mat mat = new Mat(@$"..\..\..\Assets\AutoFishing\{screenshot1080p}");
var imageRegion = new GameCaptureRegion(mat, 0, 0, new DesktopRegion(new FakeMouseSimulator()), converter: new ScaleConverter(1d), drawContent: new FakeDrawContent());
var blackboard = new Blackboard(Predictor, sleep: i => { })
{
selectedBaitName = selectedBaitName
};
FakeTimeProvider fakeTimeProvider = new FakeTimeProvider();
//
ThrowRod sut = new ThrowRod("-", blackboard, true, new FakeLogger(), false, new FakeInputSimulator(), fakeTimeProvider, drawContent: new FakeDrawContent());
BehaviourStatus actual = sut.Tick(imageRegion);
//
Assert.False(blackboard.throwRodNoBaitFish);
Assert.Equal(BehaviourStatus.Succeeded, actual);
}
[Theory]
[InlineData(@"20250225101304534_ThrowRod_Succeeded.png", "redrot bait")]
[InlineData(@"20250225101304534_ThrowRod_Succeeded.png", "fake fly bait")]
///
/// 测试各种抛竿,未满足HutaoFisher判定,结果为运行中
///
public void ThrowRodTest_VariousFish_ShouldFail(string screenshot1080p, string selectedBaitName)
{
//
Mat mat = new Mat(@$"..\..\..\Assets\AutoFishing\{screenshot1080p}");
var imageRegion = new GameCaptureRegion(mat, 0, 0, new DesktopRegion(new FakeMouseSimulator()), converter: new ScaleConverter(1d), drawContent: new FakeDrawContent());
var blackboard = new Blackboard(Predictor, sleep: i => { })
{
selectedBaitName = selectedBaitName
};
FakeTimeProvider fakeTimeProvider = new FakeTimeProvider();
//
ThrowRod sut = new ThrowRod("-", blackboard, this.useTorch, new FakeLogger(), false, new FakeInputSimulator(), fakeTimeProvider, drawContent: new FakeDrawContent());
BehaviourStatus actual = sut.Tick(imageRegion);
//
Assert.False(blackboard.throwRodNoBaitFish);
Assert.Equal(BehaviourStatus.Running, actual);
}
[Theory]
[InlineData(@"20250225101304534_ThrowRod_Succeeded.png", "flashing maintenance mek bait")]
///
/// 测试各种抛竿,无鱼饵适用鱼,结果为失败
///
public void ThrowRodTest_NoBaitFish_ShouldFail(string screenshot1080p, string selectedBaitName)
{
//
Mat mat = new Mat(@$"..\..\..\Assets\AutoFishing\{screenshot1080p}");
var imageRegion = new GameCaptureRegion(mat, 0, 0, new DesktopRegion(new FakeMouseSimulator()), converter: new ScaleConverter(1d), drawContent: new FakeDrawContent());
var blackboard = new Blackboard(Predictor, sleep: i => { })
{
selectedBaitName = selectedBaitName
};
FakeTimeProvider fakeTimeProvider = new FakeTimeProvider();
//
ThrowRod sut = new ThrowRod("-", blackboard, this.useTorch, new FakeLogger(), false, new FakeInputSimulator(), fakeTimeProvider, drawContent: new FakeDrawContent());
BehaviourStatus actual = sut.Tick(imageRegion);
//
Assert.False(blackboard.throwRodNoBaitFish);
Assert.Equal(BehaviourStatus.Running, actual);
//
// Do nothing
//
for (int i = 0; i < 10; i++)
{
sut.Tick(imageRegion);
}
//
Assert.True(blackboard.throwRodNoBaitFish);
}
///
/// 抛竿时,给定三条炮鲀鱼,并且确定算法能将下杆点从鱼的左侧移动到最左侧的炮鲀鱼上,此时希望“当前鱼”能始终锁定在最左侧的鱼上
/// 由于偶尔观测到“摇摆”行为的出现,故设计此测试
///
[Fact]
public void ThrowRodTest_Target_ShouldBeTheLeftOne()
{
//
Mat mat = new Mat(@$"..\..\..\Assets\AutoFishing\202503082114541115.png");
var imageRegion = new GameCaptureRegion(mat, 0, 0, new DesktopRegion(new FakeMouseSimulator()), converter: new ScaleConverter(1d), drawContent: new FakeDrawContent());
var blackboard = new Blackboard(Predictor, sleep: i => { })
{
selectedBaitName = "fake fly bait"
};
//
ThrowRod sut = new ThrowRod("-", blackboard, this.useTorch, new FakeLogger(), false, new FakeInputSimulator(), new FakeTimeProvider(), drawContent: new FakeDrawContent());
sut.Tick(imageRegion);
var actual = sut.currentFish;
//
Assert.True(blackboard.fishpond.TargetRect != null && blackboard.fishpond.TargetRect.Value != default);
Assert.Equal(3, blackboard.fishpond.Fishes.Count(f => f.FishType.Name == "pufferfish"));
Assert.Equal(blackboard.fishpond.Fishes.OrderBy(f => f.Rect.X).First(), actual);
//
mat = new Mat(@$"..\..\..\Assets\AutoFishing\202503082114560489.png");
imageRegion = new GameCaptureRegion(mat, 0, 0, new DesktopRegion(new FakeMouseSimulator()), converter: new ScaleConverter(1d), drawContent: new FakeDrawContent());
//
sut.Tick(imageRegion);
actual = sut.currentFish;
//
Assert.Equal(3, blackboard.fishpond.Fishes.Count(f => f.FishType.Name == "pufferfish"));
Assert.Equal(blackboard.fishpond.Fishes.OrderBy(f => f.Rect.X).First(), actual);
}
[Theory]
[InlineData(@"202502252347412417.png")]
[InlineData(@"202503012143011486@900p.png")]
///
/// 测试各种抛竿,超时未找到落点,结果为失败
///
public void ThrowRodTest_NoTarget_ShouldFail(string screenshot1080p)
{
//
Mat mat = new Mat(@$"..\..\..\Assets\AutoFishing\{screenshot1080p}");
var imageRegion = new GameCaptureRegion(mat, 0, 0, new DesktopRegion(new FakeMouseSimulator()), converter: new ScaleConverter(1d), drawContent: new FakeDrawContent());
var blackboard = new Blackboard(Predictor, sleep: i => { });
FakeTimeProvider fakeTimeProvider = new FakeTimeProvider();
//
ThrowRod sut = new ThrowRod("-", blackboard, this.useTorch, new FakeLogger(), false, new FakeInputSimulator(), fakeTimeProvider, drawContent: new FakeDrawContent());
BehaviourStatus actual = sut.Tick(imageRegion);
//
Assert.False(blackboard.throwRodNoTarget);
Assert.Equal(BehaviourStatus.Running, actual);
//
fakeTimeProvider.Advance(TimeSpan.FromSeconds(5.1));
//
actual = sut.Tick(imageRegion);
//
Assert.True(blackboard.throwRodNoTarget);
Assert.Equal(BehaviourStatus.Failed, actual);
}
[Theory]
[InlineData(@"202502252347412417.png")]
///
/// 测试抛竿循环,3次超时未找到落点,结果为失败并退出
///
public void ThrowRodTest_NoTarget_3Times_ShouldFailAndAbort(string screenshot1080p)
{
//
Mat mat = new Mat(@$"..\..\..\Assets\AutoFishing\{screenshot1080p}");
FakeInputSimulator input = new FakeInputSimulator();
FakeDrawContent drawContent = new FakeDrawContent();
var imageRegion = new GameCaptureRegion(mat, 0, 0, new DesktopRegion(input.Mouse), converter: new ScaleConverter(1d), drawContent: drawContent);
var blackboard = new Blackboard(Predictor, sleep: i => { });
FakeTimeProvider timeProvider = new FakeTimeProvider();
FakeLogger logger = new FakeLogger();
//
var sut = FluentBuilder.Create()
.MySimpleParallel("抛竿直到成功或出错", policy: SimpleParallelPolicy.OnlyOneMustSucceed)
.UntilSuccess("重复抛竿")
.Sequence("-")
.PushLeaf(() => new MoveViewpointDown("调整视角至俯视", blackboard, logger, false, input))
.PushLeaf(() => new ThrowRod("抛竿", blackboard, this.useTorch, logger, false, input, timeProvider, drawContent))
.End()
.End()
.Do("抛竿检查", _ => (blackboard.abort || blackboard.throwRodNoTarget || blackboard.throwRodNoBaitFish) ? BehaviourStatus.Failed : BehaviourStatus.Running)
.End()
.Build();
sut.Tick(imageRegion);
sut.Tick(imageRegion);
timeProvider.Advance(TimeSpan.FromSeconds(5.1));
BehaviourStatus actual = sut.Tick(imageRegion);
//
Assert.True(blackboard.throwRodNoTarget);
Assert.Equal(1, blackboard.throwRodNoTargetTimes);
Assert.Equal(BehaviourStatus.Failed, actual);
//
//
sut.Tick(imageRegion);
sut.Tick(imageRegion);
timeProvider.Advance(TimeSpan.FromSeconds(5.1));
actual = sut.Tick(imageRegion);
//
Assert.True(blackboard.throwRodNoTarget);
Assert.Equal(2, blackboard.throwRodNoTargetTimes);
Assert.Equal(BehaviourStatus.Failed, actual);
//
//
sut.Tick(imageRegion);
sut.Tick(imageRegion);
timeProvider.Advance(TimeSpan.FromSeconds(5.1));
actual = sut.Tick(imageRegion);
//
Assert.True(blackboard.throwRodNoTarget);
Assert.Equal(3, blackboard.throwRodNoTargetTimes);
Assert.Equal(BehaviourStatus.Failed, actual);
Assert.True(blackboard.abort);
}
}
}