Skip to content

Commit

Permalink
add linkshell support
Browse files Browse the repository at this point in the history
  • Loading branch information
Koenari committed Dec 22, 2024
1 parent a5b9ea4 commit d5a2e55
Show file tree
Hide file tree
Showing 12 changed files with 478 additions and 12 deletions.
6 changes: 3 additions & 3 deletions NetStone.Test/NetStone.Test.csproj
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>

<IsPackable>false</IsPackable>
<LangVersion>10.0</LangVersion>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="NUnit" Version="3.13.3" />
<PackageReference Include="NUnit3TestAdapter" Version="4.2.1" />
<PackageReference Include="NUnit" Version="3.14.0" />
<PackageReference Include="NUnit3TestAdapter" Version="4.6.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.2" />
</ItemGroup>

Expand Down
24 changes: 24 additions & 0 deletions NetStone.Test/Tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -586,4 +586,28 @@ public async Task CheckCrossworldLinkShell()
}

}

[Test]
public async Task CheckLinkshell()
{
var ls = await this.lodestone.GetLinkshell(TestLinkshell);
Assert.IsNotNull(ls);
Assert.AreEqual("CORshell", ls.Name);
Assert.AreEqual(2, ls.NumPages);
while (ls is not null)
{
foreach (var member in ls.Members)
{
Console.WriteLine($"{member.Name} ({member.Rank}) {member.RankIcon}\n" +
$"Id: {member.Id}\n" +
$"Avatar: {member.Avatar}\n" +
$"Server: {member.Server}\n" +
$"LS Rank: {member.LinkshellRank}\n" +
$"LS Rank Icon: {member.LinkshellRankIcon}");

}
ls = await ls.GetNextPage();
}

}
}
13 changes: 12 additions & 1 deletion NetStone/Definitions/DefinitionsContainer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using NetStone.Definitions.Model.Character;
using NetStone.Definitions.Model.CWLS;
using NetStone.Definitions.Model.FreeCompany;
using NetStone.Definitions.Model.Linkshell;

namespace NetStone.Definitions;

Expand Down Expand Up @@ -91,9 +92,19 @@ public abstract class DefinitionsContainer : IDisposable
public CrossWorldLinkShellDefinition CrossWorldLinkShell { get; protected set; }

/// <summary>
/// Definitions for cross world link shell memebrs
/// Definitions for cross world link shell members
/// </summary>
public CrossWorldLinkShellMemberDefinition CrossWorldLinkShellMember { get; protected set; }

/// <summary>
/// Definitions for link shells
/// </summary>
public LinkShellDefinition LinkShell { get; protected set; }

/// <summary>
/// Definitions for link shell members
/// </summary>
public LinkShellMemberDefinition LinkShellMember { get; protected set; }

#endregion

Expand Down
15 changes: 15 additions & 0 deletions NetStone/Definitions/Model/Linkshell/LinkShellDefinition.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using Newtonsoft.Json;

namespace NetStone.Definitions.Model.Linkshell;

/// <summary>
/// Definitions for link shell
/// </summary>
public class LinkShellDefinition : IDefinition
{
/// <summary>
/// Name
/// </summary>
[JsonProperty("NAME")]
public DefinitionsPack Name { get; set; }
}
57 changes: 57 additions & 0 deletions NetStone/Definitions/Model/Linkshell/LinkShellMemberDefinition.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
using Newtonsoft.Json;

namespace NetStone.Definitions.Model.Linkshell;

/// <summary>
/// Definition for the list of linkshell members
/// </summary>
public class LinkShellMemberDefinition : PagedDefinition<LinkShellMemberEntryDefinition>
{

}

/// <summary>
/// Definition for one entry of the linkshell memebr list
/// </summary>
public class LinkShellMemberEntryDefinition : PagedEntryDefinition
{
/// <summary>
/// Avatar
/// </summary>
[JsonProperty("AVATAR")] public DefinitionsPack Avatar { get; set; }

/// <summary>
/// ID
/// </summary>
[JsonProperty("ID")] public DefinitionsPack Id { get; set; }

/// <summary>
/// Name
/// </summary>
[JsonProperty("NAME")] public DefinitionsPack Name { get; set; }

/// <summary>
/// Rank
/// </summary>
[JsonProperty("RANK")] public DefinitionsPack Rank { get; set; }

/// <summary>
/// Rank Icon
/// </summary>
[JsonProperty("RANK_ICON")] public DefinitionsPack RankIcon { get; set; }

/// <summary>
/// Linkshell rank
/// </summary>
[JsonProperty("LINKSHELL_RANK")] public DefinitionsPack LinkshellRank { get; set; }

/// <summary>
/// Linkshell rank Icon
/// </summary>
[JsonProperty("LINKSHELL_RANK_ICON")] public DefinitionsPack LinkshellRankIcon { get; set; }

/// <summary>
/// Server
/// </summary>
[JsonProperty("SERVER")] public DefinitionsPack Server { get; set; }
}
4 changes: 4 additions & 0 deletions NetStone/Definitions/XivApiDefinitionsContainer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using NetStone.Definitions.Model.Character;
using NetStone.Definitions.Model.CWLS;
using NetStone.Definitions.Model.FreeCompany;
using NetStone.Definitions.Model.Linkshell;
using Newtonsoft.Json;

namespace NetStone.Definitions;
Expand Down Expand Up @@ -59,6 +60,9 @@ public override async Task Reload()

this.CrossWorldLinkShell = await GetDefinition<CrossWorldLinkShellDefinition>("cwls/cwls.json");
this.CrossWorldLinkShellMember = await GetDefinition<CrossWorldLinkShellMemberDefinition>("cwls/members.json");

this.LinkShell = await GetDefinition<LinkShellDefinition>("linkshell/ls.json");
this.LinkShellMember = await GetDefinition<LinkShellMemberDefinition>("linkshell/members.json");
}

private async Task<T> GetDefinition<T>(string path) where T : IDefinition
Expand Down
21 changes: 18 additions & 3 deletions NetStone/LodestoneClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@
using NetStone.Model.Parseables.Character.ClassJob;
using NetStone.Model.Parseables.Character.Collectable;
using NetStone.Model.Parseables.CWLS;
using NetStone.Model.Parseables.CWLS.Members;
using NetStone.Model.Parseables.FreeCompany;
using NetStone.Model.Parseables.FreeCompany.Members;
using NetStone.Model.Parseables.Linkshell;
using NetStone.Model.Parseables.Search.Character;
using NetStone.Model.Parseables.Search.FreeCompany;
using NetStone.Search.Character;
Expand Down Expand Up @@ -148,16 +148,31 @@ await GetParsed(
public async Task<CharacterSearchPage?> SearchCharacter(CharacterSearchQuery query, int page = 1) =>
await GetParsed($"/lodestone/character/{query.BuildQueryString()}&page={page}",
node => new CharacterSearchPage(this, node, this.Definitions.CharacterSearch, query));

#endregion

#region Linkshells
/// <summary>
/// Get's a cross world link shell by it's id.
/// Gets a cross world link shell by its id.
/// </summary>
/// <param name="id">The ID of the cross world linkshell.</param>
/// <param name="page"></param>
/// <returns><see cref="LodestoneCrossWorldLinkShell"/> class containing information about the cross world link shell</returns>
public async Task<LodestoneCrossWorldLinkShell?> GetCrossworldLinkshell(string id, int page = 1) =>
await GetParsed($"/lodestone/crossworld_linkshell/{id}?page={page}",
node => new LodestoneCrossWorldLinkShell(this, node, this.Definitions,id));



/// <summary>
/// Gets a link shell by its id.
/// </summary>
/// <param name="id">The ID of the linkshell.</param>
/// <param name="page"></param>
/// <returns><see cref="LodestoneCrossWorldLinkShell"/> class containing information about the cross world link shell</returns>
public async Task<LodestoneLinkShell?> GetLinkshell(string id, int page = 1) =>
await GetParsed($"/lodestone/linkshell/{id}?page={page}",
node => new LodestoneLinkShell(this, node, this.Definitions,id));

#endregion

#region FreeCompany
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,11 @@ public CharacterAchievementEntry(HtmlNode rootNode, CharacterAchievementEntryDef
/// <summary>
/// The Name of this achievement
/// </summary>
#if NETSTANDARD2_1
public string Name => ParseRegex(this.definition.Name).First(r => r.Name.Equals("Name")).Value;

#else
public string Name => ParseRegex(this.definition.Name).Values.First(r => r.Name.Equals("Name")).Value;
#endif
/// <summary>
/// ID of this achievement
/// </summary>
Expand Down
113 changes: 113 additions & 0 deletions NetStone/Model/Parseables/Linkshell/LodestoneLinkShell.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using HtmlAgilityPack;
using NetStone.Definitions;
using NetStone.Definitions.Model.Linkshell;
using NetStone.Model.Parseables.Linkshell.Members;

namespace NetStone.Model.Parseables.Linkshell;

/// <summary>
/// Container class holding information about a linkshell and it's members.
/// </summary>
public class LodestoneLinkShell : LodestoneParseable, IPaginatedResult<LodestoneLinkShell>
{
private readonly LodestoneClient client;

private readonly string lsId;

private readonly LinkShellDefinition lsDefinition;
private readonly LinkShellMemberDefinition pageDefinition;

/// <summary>
/// Container class for a parseable linkshell page.
/// </summary>
/// <param name="client">The <see cref="LodestoneClient"/> to be used to fetch further information.</param>
/// <param name="rootNode">The root document node of the page.</param>
/// <param name="container">The <see cref="DefinitionsContainer"/> holding definitions to be used to access data.</param>
/// <param name="id">The ID of the cross world linkshell.</param>
public LodestoneLinkShell(LodestoneClient client, HtmlNode rootNode, DefinitionsContainer container, string id) : base(rootNode)
{
this.client = client;
this.lsId = id;
this.lsDefinition = container.LinkShell;
this.pageDefinition = container.LinkShellMember;
}

/// <summary>
/// Name
/// </summary>
public string Name => Parse(this.lsDefinition.Name);


private LinkShellMemberEntry[]? parsedResults;

/// <summary>
/// List of members
/// </summary>
public IEnumerable<LinkShellMemberEntry> Members
{
get
{
if (this.parsedResults == null)
ParseSearchResults();

return this.parsedResults!;
}
}

private void ParseSearchResults()
{
var nodes = QueryContainer(this.pageDefinition);

this.parsedResults = new LinkShellMemberEntry[nodes.Length];
for (var i = 0; i < this.parsedResults.Length; i++)
{
this.parsedResults[i] = new LinkShellMemberEntry(nodes[i], this.pageDefinition.Entry);
}
}

private int? currentPageVal;

///<inheritdoc />
public int CurrentPage
{
get
{
if (!this.currentPageVal.HasValue)
ParsePagesCount();

return this.currentPageVal!.Value;
}
}

private int? numPagesVal;

/// <inheritdoc/>
public int NumPages
{
get
{
if (!this.numPagesVal.HasValue)
ParsePagesCount();

return this.numPagesVal!.Value;
}
}
private void ParsePagesCount()
{
var results = ParseRegex(this.pageDefinition.PageInfo);

this.currentPageVal = int.Parse(results["CurrentPage"].Value);
this.numPagesVal = int.Parse(results["NumPages"].Value);
}

/// <inheritdoc />
public async Task<LodestoneLinkShell?> GetNextPage()
{
if (this.CurrentPage == this.NumPages)
return null;

return await this.client.GetLinkshell(this.lsId, this.CurrentPage + 1);
}
}
Loading

0 comments on commit d5a2e55

Please sign in to comment.