-
-
Notifications
You must be signed in to change notification settings - Fork 33
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
I have implemented the campaign skip (story skip) functionality. When the "Skip Campaign" button is clicked on the client application (only visible when player has not cleared chapter 10), player data will be adjusted as described in the Dragalia Lost Wiki. - Player level: 60 - Stamina: 999 - Getherwings: 99 - All quest first clear and endeavors completed on Easy mode from chapters 1-10, granting Wyrmite rewards - All quest stories marked as "read" from chapters 1-10 - Story units and dragon rewards added to collection - Tutorials skipped through chapter 10 - Story progression Halidom facilities added to storage with their appropriate levels I also included a fairly detailed unit test, which will check player level, Halidom buildings, etc. [Api Doc](https://dragalia-api-docs.readthedocs.io/en/latest/dragalia/story_skip_skip.html) [Dragalia Lost Wiki](https://dragalialost.wiki/w/Beginner%27s_Guide#The_Story_Skip_Option) This was my first dive into a C# web app, so hopefully my code fits with your coding conventions.
- Loading branch information
1 parent
de86dca
commit f6016cc
Showing
6 changed files
with
541 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
102 changes: 102 additions & 0 deletions
102
DragaliaAPI/DragaliaAPI.Integration.Test/Features/StorySkip/StorySkipTest.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | ||
} | ||
} | ||
} | ||
} |
58 changes: 58 additions & 0 deletions
58
DragaliaAPI/DragaliaAPI.Shared/Features/StorySkip/StorySkipRewards.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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
65
DragaliaAPI/DragaliaAPI/Features/StorySkip/StorySkipController.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 }); | ||
} | ||
} |
Oops, something went wrong.