Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Campaign skip feature #777

Merged
merged 13 commits into from
May 7, 2024
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ public interface IQuestRepository
{
IQueryable<DbQuest> Quests { get; }
IQueryable<DbQuestEvent> QuestEvents { get; }
IQueryable<DbQuestTreasureList> QuestTreasureList { get; }

Task<DbQuest> GetQuestDataAsync(int questId);
Task<DbQuestEvent> GetQuestEventAsync(int questEventId);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
using DragaliaAPI.Database.Entities;
using DragaliaAPI.Features.StorySkip;
using DragaliaAPI.Shared.Features.StorySkip;
using Microsoft.EntityFrameworkCore;
using static DragaliaAPI.Shared.Features.StorySkip.StorySkipRewards;

namespace DragaliaAPI.Integration.Test.Features.StorySkip;

/// <summary>
/// Tests <see cref="StorySkipController"/>
/// </summary>
public class StorySkipTest : TestFixture
{
public StorySkipTest(CustomWebApplicationFactory factory, ITestOutputHelper testOutputHelper)
: base(factory, testOutputHelper) { }

[Fact]
public async Task StorySkip_CheckStatsAfterSkip()
{
int questId = 100_100_107;
int storyId = 1_001_009;
Dictionary<FortPlants, FortConfig> fortConfigs = StorySkipRewards.FortConfigs;
List<FortPlants> uniqueFortPlants = new(fortConfigs.Keys);

await this
.ApiContext.PlayerUserData.Where(x => x.ViewerId == this.ViewerId)
.ExecuteUpdateAsync(u =>
u.SetProperty(e => e.Level, 5)
.SetProperty(e => e.Exp, 1)
.SetProperty(e => e.StaminaSingle, 10)
.SetProperty(e => e.StaminaMulti, 10)
);

await this
.ApiContext.PlayerQuests.Where(x => x.ViewerId == this.ViewerId && x.QuestId <= questId)
.ExecuteDeleteAsync();

await this
.ApiContext.PlayerStoryState.Where(x =>
x.ViewerId == this.ViewerId
&& x.StoryType == StoryTypes.Quest
&& x.StoryId <= storyId
)
.ExecuteDeleteAsync();

await this
.ApiContext.PlayerCharaData.Where(x =>
x.ViewerId == this.ViewerId && x.CharaId != Charas.ThePrince
)
.ExecuteDeleteAsync();

await this
.ApiContext.PlayerDragonData.Where(x => x.ViewerId == this.ViewerId)
.ExecuteDeleteAsync();

await this
.ApiContext.PlayerFortBuilds.Where(x => x.ViewerId == this.ViewerId)
.ExecuteDeleteAsync();

StorySkipSkipResponse data = (
await this.Client.PostMsgpack<StorySkipSkipResponse>("story_skip/skip")
).Data;

DbPlayerUserData userData = await this.ApiContext.PlayerUserData.SingleAsync(x =>
x.ViewerId == this.ViewerId
);

data.Should().BeEquivalentTo(new StorySkipSkipResponse() { ResultState = 1 });
userData.Level.Should().Be(60);
userData.Exp.Should().Be(69990);
userData.StaminaSingle.Should().Be(999);
userData.StaminaMulti.Should().Be(99);
userData.TutorialFlag.Should().Be(16640603);
userData.TutorialStatus.Should().Be(60999);
this.ApiContext.PlayerQuests.Count(x => x.ViewerId == this.ViewerId && x.QuestId == questId)
.Should()
.Be(1);
this.ApiContext.PlayerStoryState.Count(x =>
x.ViewerId == this.ViewerId && x.StoryId == storyId
)
.Should()
.Be(1);
this.ApiContext.PlayerCharaData.Count(x => x.ViewerId == this.ViewerId).Should().Be(6);
this.ApiContext.PlayerDragonData.Count(x => x.ViewerId == this.ViewerId).Should().Be(5);

foreach ((FortPlants fortPlant, FortConfig fortConfig) in fortConfigs)
{
List<DbFortBuild> forts = await this
.ApiContext.PlayerFortBuilds.Where(x =>
x.ViewerId == this.ViewerId && x.PlantId == fortPlant
)
.ToListAsync();

forts.Count.Should().Be(fortConfig.BuildCount);

foreach (DbFortBuild fort in forts)
{
fort.Level.Should().Be(fortConfig.Level);
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
using DragaliaAPI.Shared.Definitions.Enums;

namespace DragaliaAPI.Shared.Features.StorySkip;

public static class StorySkipRewards
{
public struct FortConfig
{
public int BuildCount { get; }
public int Level { get; }
public int PositionX { get; }
public int PositionZ { get; }

public FortConfig(int level, int buildCount, int positionX = -1, int positionZ = -1)
{
BuildCount = buildCount;
Level = level;
PositionX = positionX;
PositionZ = positionZ;
}
}

public static readonly List<Charas> CharasList =
new() { Charas.Elisanne, Charas.Ranzal, Charas.Cleo, Charas.Luca, Charas.Alex };

public static readonly List<Dragons> DragonList =
new()
{
Dragons.Brunhilda,
Dragons.Mercury,
Dragons.Midgardsormr,
Dragons.Jupiter,
Dragons.Zodiark,
};

public static readonly Dictionary<FortPlants, FortConfig> FortConfigs =
new()
{
[FortPlants.TheHalidom] = new FortConfig(6, 1, 16, 17),
[FortPlants.Smithy] = new FortConfig(6, 1, 21, 3),
[FortPlants.RupieMine] = new FortConfig(15, 4),
[FortPlants.Dragontree] = new FortConfig(15, 1),
[FortPlants.FlameAltar] = new FortConfig(10, 2),
[FortPlants.WaterAltar] = new FortConfig(10, 2),
[FortPlants.WindAltar] = new FortConfig(10, 2),
[FortPlants.LightAltar] = new FortConfig(10, 2),
[FortPlants.ShadowAltar] = new FortConfig(10, 2),
[FortPlants.SwordDojo] = new FortConfig(10, 2),
[FortPlants.BladeDojo] = new FortConfig(10, 2),
[FortPlants.DaggerDojo] = new FortConfig(10, 2),
[FortPlants.LanceDojo] = new FortConfig(10, 2),
[FortPlants.AxeDojo] = new FortConfig(10, 2),
[FortPlants.BowDojo] = new FortConfig(10, 2),
[FortPlants.WandDojo] = new FortConfig(10, 2),
[FortPlants.StaffDojo] = new FortConfig(10, 2),
[FortPlants.ManacasterDojo] = new FortConfig(10, 2)
};
}
65 changes: 65 additions & 0 deletions DragaliaAPI/DragaliaAPI/Features/StorySkip/StorySkipController.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
using DragaliaAPI.Controllers;
using DragaliaAPI.Database.Repositories;
using DragaliaAPI.Models.Generated;
using DragaliaAPI.Services;
using DragaliaAPI.Shared.PlayerDetails;
using Microsoft.AspNetCore.Mvc;

namespace DragaliaAPI.Features.StorySkip;

[Route("story_skip")]
public class StorySkipController : DragaliaControllerBase
{
private readonly ILogger<StorySkipController> logger;
private readonly IPlayerIdentityService playerIdentityService;
private readonly IQuestRepository questRepository;
private readonly StorySkipService storySkipService;
private readonly IUpdateDataService updateDataService;
private readonly IUserDataRepository userDataRepository;

public StorySkipController(
ILogger<StorySkipController> logger,
IPlayerIdentityService playerIdentityService,
IQuestRepository questRepository,
StorySkipService storySkipService,
IUpdateDataService updateDataService,
IUserDataRepository userDataRepository
)
{
this.logger = logger;
this.playerIdentityService = playerIdentityService;
this.questRepository = questRepository;
this.storySkipService = storySkipService;
this.updateDataService = updateDataService;
this.userDataRepository = userDataRepository;
}

[HttpPost("skip")]
public async Task<DragaliaResult> Read(CancellationToken cancellationToken)
{
string accountId = playerIdentityService.AccountId;
long viewerId = playerIdentityService.ViewerId;

this.logger.LogDebug("Beginning story skip for player {accountId}.", accountId);

int wyrmite1 = await storySkipService.ProcessQuestCompletions(viewerId);
this.logger.LogDebug("Wyrmite earned from quests: {wyrmite}", wyrmite1);

int wyrmite2 = await storySkipService.ProcessStoryCompletions(viewerId);
this.logger.LogDebug("Wyrmite earned from quest stories: {wyrmite}", wyrmite2);

await storySkipService.UpdateUserData(wyrmite1 + wyrmite2);

await storySkipService.IncreaseFortLevels(viewerId);

await storySkipService.RewardCharas(viewerId);

await storySkipService.RewardDragons(viewerId);

await updateDataService.SaveChangesAsync(cancellationToken);

this.logger.LogDebug("Story Skip completed for player {accountId}.", accountId);

return this.Ok(new StorySkipSkipResponse() { ResultState = 1 });
}
}
Loading
Loading