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)) 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); } 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; + //} } 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