From d33cb6ce17ee6ac8e175bd8a32106d3e1cf2b983 Mon Sep 17 00:00:00 2001 From: Macocian Alexandru Victor Date: Mon, 30 Jun 2025 10:13:41 +0200 Subject: [PATCH 1/4] Release 0.9.9.77 (#1033) --- Directory.Build.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Directory.Build.props b/Directory.Build.props index cc24117c..4af462bc 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -2,7 +2,7 @@ $(NoWarn);IL2104;IL3053;IL3000;IL3002;NU1701;CS0108 - 0.9.9.76 + 0.9.9.77 enable enable From 4ec5ae0683bf5702e01929f11e2d7d334bf01510 Mon Sep 17 00:00:00 2001 From: Macocian Alexandru Victor Date: Mon, 30 Jun 2025 10:17:30 +0200 Subject: [PATCH 2/4] Fix build codes not applying due to unescaped url characters (Closes #1032) (#1034) --- Daybreak.Shared/Services/Api/ScopedApiContext.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Daybreak.Shared/Services/Api/ScopedApiContext.cs b/Daybreak.Shared/Services/Api/ScopedApiContext.cs index 477ba5b6..273a60bd 100644 --- a/Daybreak.Shared/Services/Api/ScopedApiContext.cs +++ b/Daybreak.Shared/Services/Api/ScopedApiContext.cs @@ -4,6 +4,7 @@ using System.Extensions.Core; using System.Net.Http; using System.Net.Http.Json; +using System.Text.Encodings.Web; namespace Daybreak.Shared.Services.Api; public sealed class ScopedApiContext( @@ -74,7 +75,8 @@ public async Task SwitchCharacter(string characterName, CancellationToken public async Task PostMainPlayerBuild(string code, CancellationToken cancellationToken) { - var path = PostMainPlayerBuildPath.Replace(CodePlaceholder, code); + var encodedBuildCode = UrlEncoder.Default.Encode(code); + var path = PostMainPlayerBuildPath.Replace(CodePlaceholder, encodedBuildCode); using var emptyContent = new StringContent(string.Empty); return await this.Post(path, request => emptyContent, cancellationToken); } From eb1921ec7417cf95cc6fae3e8ba7a4f227acb2c0 Mon Sep 17 00:00:00 2001 From: Macocian Alexandru Victor Date: Mon, 30 Jun 2025 10:22:44 +0200 Subject: [PATCH 3/4] Fix builds not showing in FocusView due to locked skills (Closes #1031) (#1035) --- .../BuildTemplates/BuildTemplateManager.cs | 50 +++++-------------- 1 file changed, 13 insertions(+), 37 deletions(-) diff --git a/Daybreak.Shared/Services/BuildTemplates/BuildTemplateManager.cs b/Daybreak.Shared/Services/BuildTemplates/BuildTemplateManager.cs index d48db8b9..a2419a61 100644 --- a/Daybreak.Shared/Services/BuildTemplates/BuildTemplateManager.cs +++ b/Daybreak.Shared/Services/BuildTemplates/BuildTemplateManager.cs @@ -204,15 +204,6 @@ public bool CanApply(MainPlayerBuildContext mainPlayerBuildContext, TeamBuildEnt return (build, compositionEntry, index); }); - var lockedSkill = loadoutEntryComposition - .Select(entry => entry.build.Skills.FirstOrDefault(s => s != Skill.NoSkill && !IsSkillUnlocked(s.Id, mainPlayerBuildContext.UnlockedAccountSkills))) - .OfType() - .FirstOrDefault(); - if (lockedSkill is not null) - { - scopedLogger.LogDebug("Invalid team build entry {buildName}. Skill {skillName} is not unlocked by the current account", teamBuildEntry.Name ?? string.Empty, lockedSkill.Name); - } - return loadoutEntryComposition.Any(entry => entry.compositionEntry.Type is PartyCompositionMemberType.MainPlayer && this.CanApply(mainPlayerBuildContext, entry.build)); } @@ -232,12 +223,6 @@ public bool CanApply(MainPlayerBuildContext mainPlayerBuildContext, SingleBuildE return false; } - if (singleBuildEntry.Skills.FirstOrDefault(s => s != Skill.NoSkill && !IsSkillUnlocked(s.Id, mainPlayerBuildContext.UnlockedCharacterSkills)) is Skill lockedSkill) - { - scopedLogger.LogDebug("Invalid build entry {buildName}. Skill {skillName} is not unlocked by the current character", singleBuildEntry.Name ?? string.Empty, lockedSkill.Name); - return false; - } - return true; } @@ -257,16 +242,6 @@ public bool CanTemplateApply(BuildTemplateValidationRequest request) return false; } - foreach(var skill in request.BuildSkills) - { - if (skill is not 0 && - !IsSkillUnlocked((int)skill, request.UnlockedSkills)) - { - scopedLogger.LogError("Skill {skillId} is not unlocked", skill); - return false; - } - } - return true; } @@ -872,16 +847,17 @@ private static int FromBitString(string bitString) private static bool IsProfessionUnlocked(int professionId, uint unlockedProfessions) => (unlockedProfessions & (1 << professionId)) != 0; - private static bool IsSkillUnlocked(int skillId, uint[] unlockedSkills) - { - var realIndex = skillId / 32; - if (realIndex >= unlockedSkills.Length) - { - return false; - } - - var shift = skillId % 32; - var flag = 1U << shift; - return (unlockedSkills[realIndex] & flag) != 0; - } + // Not using anymore. Skills are marked as locked if they are not part of the primary/secondary of the current character. Cannot rely on this for build viability checks. + //private static bool IsSkillUnlocked(int skillId, uint[] unlockedSkills) + //{ + // var realIndex = skillId / 32; + // if (realIndex >= unlockedSkills.Length) + // { + // return false; + // } + + // var shift = skillId % 32; + // var flag = 1U << shift; + // return (unlockedSkills[realIndex] & flag) != 0; + //} } From 25f2272766880329aa19aff3f992c55862ab90a6 Mon Sep 17 00:00:00 2001 From: Macocian Alexandru Victor Date: Mon, 30 Jun 2025 10:36:21 +0200 Subject: [PATCH 4/4] Sort party members by profession when applying party loadout (Closes #1030) (#1036) --- Daybreak.API/Services/PartyService.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Daybreak.API/Services/PartyService.cs b/Daybreak.API/Services/PartyService.cs index 2968599a..64ffc0ec 100644 --- a/Daybreak.API/Services/PartyService.cs +++ b/Daybreak.API/Services/PartyService.cs @@ -233,7 +233,7 @@ private unsafe bool SpawnHeroes(PartyLoadout partyLoadout) { var scopedLogger = this.logger.CreateScopedLogger(); scopedLogger.LogDebug("Spawning {heroCount} heroes for party loadout", partyLoadout.Entries.AsValueEnumerable().Count(c => c.HeroId != 0)); - foreach (var entry in partyLoadout.Entries) + foreach (var entry in partyLoadout.Entries.AsValueEnumerable().OrderBy(e => e.Build.Primary)) { if (entry.HeroId != 0 && Hero.TryParse(entry.HeroId, out var hero))