├── .github
└── workflows
│ ├── build-and-test.yaml
│ ├── manual-release.yaml
│ └── publish-nuget.yml
├── .gitignore
├── .gitmodules
├── LICENSE
├── NetStone.GameData.Lumina
├── LuminaGameDataProvider.cs
├── NetStone.GameData.Lumina.csproj
└── README.md
├── NetStone.GameData.Packs
├── Internal
│ ├── AchievementTable.cs
│ ├── ClassJobTable.cs
│ ├── DeityTable.cs
│ ├── GrandCompanyTable.cs
│ ├── ItemTable.cs
│ ├── MinionTable.cs
│ ├── MountTable.cs
│ ├── RaceTable.cs
│ ├── ReputationTable.cs
│ ├── TitleTable.cs
│ ├── TownTable.cs
│ └── TribeTable.cs
├── NetStone.GameData.Packs.csproj
└── PacksGameDataProvider.cs
├── NetStone.Test
├── NetStone.Test.csproj
└── Tests.cs
├── NetStone.sln
├── NetStone
├── Changelog.md
├── Constants.cs
├── Definitions
│ ├── .editorconfig
│ ├── DefinitionsContainer.cs
│ ├── DefinitionsPack.cs
│ ├── Model
│ │ ├── CWLS
│ │ │ ├── CrossworldLinkshellDefinition.cs
│ │ │ ├── CrossworldLinkshellMemberDefinition.cs
│ │ │ └── CrossworldLinkshellSearchDefinition.cs
│ │ ├── Character
│ │ │ ├── CharacterAchievementDefinition.cs
│ │ │ ├── CharacterAttributesDefinition.cs
│ │ │ ├── CharacterClassJobDefinition.cs
│ │ │ ├── CharacterCollectableDefinition.cs
│ │ │ ├── CharacterDefinition.cs
│ │ │ ├── CharacterGearDefinition.cs
│ │ │ └── CharacterSearchDefinition.cs
│ │ ├── FreeCompany
│ │ │ ├── FreeCompanyDefinition.cs
│ │ │ ├── FreeCompanyFocusDefinition.cs
│ │ │ ├── FreeCompanyMembersEntryDefinition.cs
│ │ │ ├── FreeCompanyReputationDefinition.cs
│ │ │ └── FreeCompanySearchDefinition.cs
│ │ ├── IDefinition.cs
│ │ ├── IconLayersDefinition.cs
│ │ ├── Linkshell
│ │ │ ├── LinkshellDefinition.cs
│ │ │ ├── LinkshellMemberDefinition.cs
│ │ │ └── LinkshellSearchEntryDefinition.cs
│ │ ├── MetaDefinition.cs
│ │ └── PagedDefinition.cs
│ └── XivApiDefinitionsContainer.cs
├── GameData
│ ├── GameDataInfo.cs
│ ├── GenderedGameData.cs
│ ├── IGameDataProvider.cs
│ ├── LanguageStrings.cs
│ ├── NamedGameData.cs
│ └── TitleGameData.cs
├── LodestoneClient.cs
├── Model
│ ├── IOptionalParseable.cs
│ ├── IPaginatedResult.cs
│ ├── LodestoneParseable.cs
│ └── Parseables
│ │ ├── CWLS
│ │ ├── LodestoneCrossworldLinkshell.cs
│ │ └── Members
│ │ │ └── CrossworldLinkshellMemberEntry.cs
│ │ ├── Character
│ │ ├── Achievement
│ │ │ ├── CharacterAchievementEntry.cs
│ │ │ └── CharacterAchievementPage.cs
│ │ ├── CharacterAttributes.cs
│ │ ├── ClassJob
│ │ │ ├── CharacterClassJob.cs
│ │ │ ├── ClassJobBozja.cs
│ │ │ ├── ClassJobEntry.cs
│ │ │ └── ClassJobEureka.cs
│ │ ├── Collectable
│ │ │ ├── CharacterCollectable.cs
│ │ │ └── CharacterCollectableEntry.cs
│ │ ├── FreeCompanySocialGroup.cs
│ │ ├── Gear
│ │ │ ├── CharacterGear.cs
│ │ │ ├── GearEntry.cs
│ │ │ └── SoulcrystalEntry.cs
│ │ └── LodestoneCharacter.cs
│ │ ├── FreeCompany
│ │ ├── FreeCompanyEstate.cs
│ │ ├── FreeCompanyFocus.cs
│ │ ├── FreeCompanyFocusEntry.cs
│ │ ├── FreeCompanyReputation.cs
│ │ ├── FreeCompanyReputationEntry.cs
│ │ ├── LodestoneFreeCompany.cs
│ │ └── Members
│ │ │ ├── FreeCompanyMembers.cs
│ │ │ └── FreeCompanyMembersEntry.cs
│ │ ├── IconLayers.cs
│ │ ├── Linkshell
│ │ ├── LodestoneLinkshell.cs
│ │ └── Members
│ │ │ └── LinkshellMemberEntry.cs
│ │ ├── Search
│ │ ├── CWLS
│ │ │ ├── CrossworldLinkshellSearchEntry.cs
│ │ │ └── CrossworldLinkshellSearchPage.cs
│ │ ├── Character
│ │ │ ├── CharacterSearchEntry.cs
│ │ │ └── CharacterSearchPage.cs
│ │ ├── FreeCompany
│ │ │ ├── FreeCompanySearchEntry.cs
│ │ │ └── FreeCompanySearchPage.cs
│ │ └── Linkshell
│ │ │ ├── LinkshellSearchEntry.cs
│ │ │ └── LinkshellSearchPage.cs
│ │ └── SocialGroup.cs
├── NetStone.csproj
├── NetStone.xml
├── Search
│ ├── Character
│ │ ├── CharacterSearchQuery.cs
│ │ └── SortKind.cs
│ ├── FreeCompany
│ │ ├── ActiveMembers.cs
│ │ ├── ActiveTimes.cs
│ │ ├── Focus.cs
│ │ ├── FreeCompanySearchQuery.cs
│ │ ├── Housing.cs
│ │ ├── Recruitment.cs
│ │ ├── Seeking.cs
│ │ └── SortKind.cs
│ ├── ISearchQuery.cs
│ └── Linkshell
│ │ └── LinkshellSearchQuery.cs
├── StaticData
│ ├── ClassJob.cs
│ ├── GrandCompany.cs
│ ├── Language.cs
│ ├── Race.cs
│ ├── Role.cs
│ └── Tribe.cs
└── UserAgent.cs
├── README.md
├── compile-fbs.sh
└── patch-flatbuffers.sh
/.github/workflows/build-and-test.yaml:
--------------------------------------------------------------------------------
1 | name: Build & Test
2 |
3 | on: [push]
4 |
5 | jobs:
6 | build:
7 | runs-on: ubuntu-latest
8 | steps:
9 | - uses: actions/checkout@v4
10 | with:
11 | submodules: recursive
12 | - name: Setup .NET
13 | uses: actions/setup-dotnet@v4
14 | with:
15 | dotnet-version: |
16 | 8.0.x
17 | 6.0.x
18 | 3.1.x
19 | - name: Install dependencies
20 | run: dotnet restore
21 | - name: Build
22 | run: dotnet build --configuration Release --no-restore
23 | - name: Test
24 | run: dotnet test --no-restore --verbosity normal
25 |
--------------------------------------------------------------------------------
/.github/workflows/manual-release.yaml:
--------------------------------------------------------------------------------
1 | name: Manual Publish (NuGet.org)
2 | on:
3 | workflow_dispatch:
4 | inputs:
5 | release-netstone:
6 | type: boolean
7 | required: true
8 | version:
9 | type: string
10 | release-lumina:
11 | type: boolean
12 | required: true
13 | lumina-version:
14 | type: string
15 | jobs:
16 | publish:
17 | runs-on: ubuntu-latest
18 | env:
19 | EXPECTED_VERSION: ${{inputs.version }}
20 | EXPECTED_LUMINA_VERSION: ${{inputs.lumina-version }}
21 | steps:
22 | - uses: actions/checkout@v4
23 | with:
24 | submodules: recursive
25 | - name: Setup .NET
26 | uses: actions/setup-dotnet@v4
27 | with:
28 | dotnet-version: 8.0.x
29 | - name: Restore dependencies
30 | run: dotnet restore
31 | - name: Build
32 | run: dotnet build --configuration Release --no-restore
33 | - name: Test
34 | run: dotnet test --configuration Release --no-build --verbosity normal
35 | - name: Package
36 | run: dotnet pack --configuration Release --no-build
37 | - name: Push package NetStone
38 | if: ${{inputs.release-netstone}}
39 | run: dotnet nuget push "**/Release/NetStone.$EXPECTED_VERSION.nupkg" --api-key ${{ secrets.NUGET_API_KEY }} --source https://api.nuget.org/v3/index.json
40 | - name: Push package NetStone.GameData.Lumina
41 | if: ${{inputs.release-lumina}}
42 | run: dotnet nuget push "**/Release/NetStone.GameData.Lumina.$EXPECTED_LUMINA_VERSION.nupkg" --api-key ${{ secrets.NUGET_API_KEY }} --source https://api.nuget.org/v3/index.json
43 |
--------------------------------------------------------------------------------
/.github/workflows/publish-nuget.yml:
--------------------------------------------------------------------------------
1 | name: Package and Publish (NuGet.org)
2 | on:
3 | push:
4 | branches:
5 | - master
6 | tags-ignore:
7 | - '*' # don't loop
8 |
9 | jobs:
10 | tag:
11 | runs-on: ubuntu-latest
12 | outputs:
13 | result: ${{steps.s1.outputs.TAG_RESULT}}
14 | version: ${{steps.s1.outputs.TAG_VERSION}}
15 | steps:
16 | - name: Determine Tag
17 | id: s1
18 | run: |
19 | version=$(echo "${{github.event.head_commit.message}}" | perl -nle 'm/build:\s*([0-9]+.[0-9]+.[0-9]+)/; print $1');
20 |
21 | if [ -z "$version" ];
22 | then
23 | echo "No build version found";
24 | echo "TAG_RESULT=fail" >> $GITHUB_OUTPUT;
25 | else
26 | export TAG_VERSION=$version;
27 | echo "TAG_VERSION=$TAG_VERSION" >> $GITHUB_OUTPUT;
28 | echo "TAG_RESULT=pass" >> $GITHUB_OUTPUT;
29 | fi
30 | - name: Create Tag
31 | if: steps.s1.outputs.TAG_RESULT == 'pass'
32 | uses: actions/github-script@v3
33 | with:
34 | github-token: ${{ github.token }}
35 | script: |
36 | github.git.createRef({
37 | owner: context.repo.owner,
38 | repo: context.repo.repo,
39 | ref: "refs/tags/v${{steps.s1.outputs.TAG_VERSION}}",
40 | sha: context.sha
41 | })
42 | tag-lumina:
43 | runs-on: ubuntu-latest
44 | outputs:
45 | result: ${{steps.s1.outputs.TAG_RESULT}}
46 | version: ${{steps.s1.outputs.TAG_VERSION}}
47 | steps:
48 | - name: Determine Tag
49 | id: s1
50 | run: |
51 | version=$(echo "${{github.event.head_commit.message}}" | perl -nle 'm/build-lumina:\s*([0-9]+.[0-9]+.[0-9]+)/; print $1');
52 |
53 | if [ -z "$version" ];
54 | then
55 | echo "No build version found";
56 | echo "TAG_RESULT=fail" >> $GITHUB_OUTPUT;
57 | else
58 | export TAG_VERSION=$version;
59 | echo "TAG_VERSION=$TAG_VERSION" >> $GITHUB_OUTPUT;
60 | echo "TAG_RESULT=pass" >> $GITHUB_OUTPUT;
61 | fi
62 | - name: Create Tag
63 | if: steps.s1.outputs.TAG_RESULT == 'pass'
64 | uses: actions/github-script@v3
65 | with:
66 | github-token: ${{ github.token }}
67 | script: |
68 | github.git.createRef({
69 | owner: context.repo.owner,
70 | repo: context.repo.repo,
71 | ref: "refs/tags/lumina-v${{steps.s1.outputs.TAG_VERSION}}",
72 | sha: context.sha
73 | })
74 | publish:
75 | runs-on: ubuntu-latest
76 | needs: [tag, tag-lumina]
77 | if: ${{needs.tag.outputs.result == 'pass' || needs.tag-lumina.outputs.result == 'pass'}}
78 | env:
79 | EXPECTED_VERSION: ${{needs.tag.outputs.version }}
80 | EXPECTED_LUMINA_VERSION: ${{needs.tag-lumina.outputs.version }}
81 | steps:
82 | - uses: actions/checkout@v4
83 | with:
84 | submodules: recursive
85 | - name: Setup .NET
86 | uses: actions/setup-dotnet@v4
87 | with:
88 | dotnet-version: 8.0.x
89 | - name: Restore dependencies
90 | run: dotnet restore
91 | - name: Build
92 | run: dotnet build --configuration Release --no-restore
93 | - name: Test
94 | run: dotnet test --configuration Release --no-build --verbosity normal
95 | - name: Package
96 | run: dotnet pack --configuration Release --no-build
97 | - name: Push package NetStone
98 | if: ${{needs.tag.outputs.result == 'pass'}}
99 | run: dotnet nuget push "**/Release/NetStone.$EXPECTED_VERSION.nupkg" --api-key ${{ secrets.NUGET_API_KEY }} --source https://api.nuget.org/v3/index.json
100 | - name: Push package NetStone.GameData.Lumina
101 | if: ${{needs.tag-lumina.outputs.result == 'pass'}}
102 | run: dotnet nuget push "**/Release/NetStone.GameData.Lumina.$EXPECTED_LUMINA_VERSION.nupkg" --api-key ${{ secrets.NUGET_API_KEY }} --source https://api.nuget.org/v3/index.json
103 |
104 |
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "lib/lodestone-data-exports"]
2 | path = lib/lodestone-data-exports
3 | url = https://github.com/karashiiro/lodestone-data-exports
4 | [submodule "lib/flatbuffers"]
5 | path = lib/flatbuffers
6 | url = https://github.com/google/flatbuffers.git
7 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2024 goaaats, Koenari
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/NetStone.GameData.Lumina/LuminaGameDataProvider.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 | using Lumina;
4 | using Lumina.Data;
5 | using Lumina.Excel;
6 | using Lumina.Excel.GeneratedSheets;
7 | using Cyalume = Lumina.GameData;
8 |
9 | namespace NetStone.GameData.Lumina;
10 |
11 | ///
12 | /// Game data provider that reads data directly from Lumina.
13 | /// This is slow and just exists as an alternative to the flatbuffer-based solution.
14 | ///
15 | public class LuminaGameDataProvider : IGameDataProvider
16 | {
17 | private readonly Cyalume lumina;
18 |
19 | ///
20 | /// Create an instance of LuminaGameDataProvider
21 | ///
22 | /// Path to game installation
23 | public LuminaGameDataProvider(DirectoryInfo gamePath)
24 | {
25 | this.lumina = new Cyalume(gamePath.FullName, new LuminaOptions{PanicOnSheetChecksumMismatch = false});
26 | }
27 |
28 | ///
29 | /// Gets infromation of an item by it's name
30 | ///
31 | /// Name of the item to search
32 | /// of the item with supplied name
33 | public NamedGameData? GetItem(string name)
34 | {
35 | var item = FindRow- (name);
36 |
37 | if (item == null)
38 | return null;
39 |
40 | var langs = CollectLanguages
- (item.RowId);
41 |
42 | return new NamedGameData
43 | {
44 | Info = new GameDataInfo
45 | {
46 | Key = item.RowId,
47 | Name = name,
48 | },
49 |
50 | Name = new LanguageStrings
51 | {
52 | En = langs.En.Name,
53 | De = langs.De.Name,
54 | Fr = langs.Fr.Name,
55 | Ja = langs.Ja.Name,
56 | },
57 | };
58 | }
59 |
60 | private (T En, T De, T Fr, T Ja) CollectLanguages(uint key) where T : ExcelRow
61 | {
62 | var en = this.lumina.Excel.GetSheet(Language.English);
63 | var de = this.lumina.Excel.GetSheet(Language.English);
64 | var fr = this.lumina.Excel.GetSheet(Language.English);
65 | var ja = this.lumina.Excel.GetSheet(Language.English);
66 |
67 | return (en!.GetRow(key)!, de!.GetRow(key)!, fr!.GetRow(key)!, ja!.GetRow(key)!);
68 | }
69 |
70 | private T? FindRow(string name) where T: ExcelRow
71 | {
72 | var en = this.lumina.Excel.GetSheet(Language.English);
73 | var de = this.lumina.Excel.GetSheet(Language.English);
74 | var fr = this.lumina.Excel.GetSheet(Language.English);
75 | var ja = this.lumina.Excel.GetSheet(Language.English);
76 |
77 | var res = FindRowInSheet(en, name);
78 | if (res != null)
79 | return res;
80 |
81 | res = FindRowInSheet(de, name);
82 | if (res != null)
83 | return res;
84 |
85 | res = FindRowInSheet(fr, name);
86 | if (res != null)
87 | return res;
88 |
89 | res = FindRowInSheet(ja, name);
90 | return res;
91 | }
92 |
93 | private static T? FindRowInSheet(ExcelSheet? sheet, string name) where T: ExcelRow
94 | {
95 | if (sheet == null)
96 | return null;
97 |
98 | foreach (var excelRow in sheet)
99 | {
100 | if (excelRow is Item item)
101 | {
102 | if (item.Name.ToString().Equals(name, StringComparison.InvariantCultureIgnoreCase))
103 | return excelRow;
104 | }
105 | }
106 |
107 | return null;
108 | }
109 | }
--------------------------------------------------------------------------------
/NetStone.GameData.Lumina/NetStone.GameData.Lumina.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net6.0
5 |
6 | NetStone.GameData.Lumina
7 | 1.1.0
8 | 1.1.0
9 | Lumina game data bindings for NetStone.
10 | goaaats
11 | https://github.com/xivapi/NetStone
12 | https://github.com/xivapi/NetStone
13 |
14 | LICENSE
15 | README.md
16 |
17 | true
18 | true
19 |
20 | 10.0
21 | enable
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 | true
35 | true
36 | snupkg
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/NetStone.GameData.Lumina/README.md:
--------------------------------------------------------------------------------
1 | # NetStone.GameData.Lumina
2 |
3 | Lumina game data bindings for NetStone.
--------------------------------------------------------------------------------
/NetStone.GameData.Packs/Internal/ItemTable.cs:
--------------------------------------------------------------------------------
1 | //
2 | // automatically generated by the FlatBuffers compiler, do not modify
3 | //
4 |
5 | namespace FFXIV
6 | {
7 |
8 | using global::System;
9 | using global::System.Collections.Generic;
10 | using global::FlatBuffers;
11 |
12 | public struct ItemTable : IFlatbufferObject
13 | {
14 | private Table __p;
15 | public ByteBuffer ByteBuffer { get { return __p.bb; } }
16 | public static void ValidateVersion() { FlatBufferConstants.FLATBUFFERS_2_0_0(); }
17 | public static ItemTable GetRootAsItemTable(ByteBuffer _bb) { return GetRootAsItemTable(_bb, new ItemTable()); }
18 | public static ItemTable GetRootAsItemTable(ByteBuffer _bb, ItemTable obj) { return (obj.__assign(_bb.GetInt(_bb.Position) + _bb.Position, _bb)); }
19 | public void __init(int _i, ByteBuffer _bb) { __p = new Table(_i, _bb); }
20 | public ItemTable __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; }
21 |
22 | public FFXIV.Item? Items(int j) { int o = __p.__offset(4); return o != 0 ? (FFXIV.Item?)(new FFXIV.Item()).__assign(__p.__indirect(__p.__vector(o) + j * 4), __p.bb) : null; }
23 | public int ItemsLength { get { int o = __p.__offset(4); return o != 0 ? __p.__vector_len(o) : 0; } }
24 | public FFXIV.Item? ItemsByKey(uint key) { int o = __p.__offset(4); return o != 0 ? FFXIV.Item.__lookup_by_key(__p.__vector(o), key, __p.bb) : null; }
25 |
26 | public static Offset CreateItemTable(FlatBufferBuilder builder,
27 | VectorOffset ItemsOffset = default(VectorOffset)) {
28 | builder.StartTable(1);
29 | ItemTable.AddItems(builder, ItemsOffset);
30 | return ItemTable.EndItemTable(builder);
31 | }
32 |
33 | public static void StartItemTable(FlatBufferBuilder builder) { builder.StartTable(1); }
34 | public static void AddItems(FlatBufferBuilder builder, VectorOffset ItemsOffset) { builder.AddOffset(0, ItemsOffset.Value, 0); }
35 | public static VectorOffset CreateItemsVector(FlatBufferBuilder builder, Offset[] data) { builder.StartVector(4, data.Length, 4); for (int i = data.Length - 1; i >= 0; i--) builder.AddOffset(data[i].Value); return builder.EndVector(); }
36 | public static VectorOffset CreateItemsVectorBlock(FlatBufferBuilder builder, Offset[] data) { builder.StartVector(4, data.Length, 4); builder.Add(data); return builder.EndVector(); }
37 | public static void StartItemsVector(FlatBufferBuilder builder, int numElems) { builder.StartVector(4, numElems, 4); }
38 | public static Offset EndItemTable(FlatBufferBuilder builder) {
39 | int o = builder.EndTable();
40 | return new Offset(o);
41 | }
42 | public static void FinishItemTableBuffer(FlatBufferBuilder builder, Offset offset) { builder.Finish(offset.Value); }
43 | public static void FinishSizePrefixedItemTableBuffer(FlatBufferBuilder builder, Offset offset) { builder.FinishSizePrefixed(offset.Value); }
44 | };
45 |
46 | public struct Item : IFlatbufferObject
47 | {
48 | private Table __p;
49 | public ByteBuffer ByteBuffer { get { return __p.bb; } }
50 | public static void ValidateVersion() { FlatBufferConstants.FLATBUFFERS_2_0_0(); }
51 | public static Item GetRootAsItem(ByteBuffer _bb) { return GetRootAsItem(_bb, new Item()); }
52 | public static Item GetRootAsItem(ByteBuffer _bb, Item obj) { return (obj.__assign(_bb.GetInt(_bb.Position) + _bb.Position, _bb)); }
53 | public void __init(int _i, ByteBuffer _bb) { __p = new Table(_i, _bb); }
54 | public Item __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; }
55 |
56 | public uint Id { get { int o = __p.__offset(4); return o != 0 ? __p.bb.GetUint(o + __p.bb_pos) : (uint)0; } }
57 | public string NameEn { get { int o = __p.__offset(6); return o != 0 ? __p.__string(o + __p.bb_pos) : null; } }
58 | #if ENABLE_SPAN_T
59 | public Span GetNameEnBytes() { return __p.__vector_as_span(6, 1); }
60 | #else
61 | public ArraySegment? GetNameEnBytes() { return __p.__vector_as_arraysegment(6); }
62 | #endif
63 | public byte[] GetNameEnArray() { return __p.__vector_as_array(6); }
64 | public string NameFr { get { int o = __p.__offset(8); return o != 0 ? __p.__string(o + __p.bb_pos) : null; } }
65 | #if ENABLE_SPAN_T
66 | public Span GetNameFrBytes() { return __p.__vector_as_span(8, 1); }
67 | #else
68 | public ArraySegment? GetNameFrBytes() { return __p.__vector_as_arraysegment(8); }
69 | #endif
70 | public byte[] GetNameFrArray() { return __p.__vector_as_array(8); }
71 | public string NameDe { get { int o = __p.__offset(10); return o != 0 ? __p.__string(o + __p.bb_pos) : null; } }
72 | #if ENABLE_SPAN_T
73 | public Span GetNameDeBytes() { return __p.__vector_as_span(10, 1); }
74 | #else
75 | public ArraySegment? GetNameDeBytes() { return __p.__vector_as_arraysegment(10); }
76 | #endif
77 | public byte[] GetNameDeArray() { return __p.__vector_as_array(10); }
78 | public string NameJa { get { int o = __p.__offset(12); return o != 0 ? __p.__string(o + __p.bb_pos) : null; } }
79 | #if ENABLE_SPAN_T
80 | public Span GetNameJaBytes() { return __p.__vector_as_span(12, 1); }
81 | #else
82 | public ArraySegment? GetNameJaBytes() { return __p.__vector_as_arraysegment(12); }
83 | #endif
84 | public byte[] GetNameJaArray() { return __p.__vector_as_array(12); }
85 |
86 | public static Offset CreateItem(FlatBufferBuilder builder,
87 | uint Id = 0,
88 | StringOffset NameEnOffset = default(StringOffset),
89 | StringOffset NameFrOffset = default(StringOffset),
90 | StringOffset NameDeOffset = default(StringOffset),
91 | StringOffset NameJaOffset = default(StringOffset)) {
92 | builder.StartTable(5);
93 | Item.AddNameJa(builder, NameJaOffset);
94 | Item.AddNameDe(builder, NameDeOffset);
95 | Item.AddNameFr(builder, NameFrOffset);
96 | Item.AddNameEn(builder, NameEnOffset);
97 | Item.AddId(builder, Id);
98 | return Item.EndItem(builder);
99 | }
100 |
101 | public static void StartItem(FlatBufferBuilder builder) { builder.StartTable(5); }
102 | public static void AddId(FlatBufferBuilder builder, uint Id) { builder.AddUint(0, Id, 0); }
103 | public static void AddNameEn(FlatBufferBuilder builder, StringOffset NameEnOffset) { builder.AddOffset(1, NameEnOffset.Value, 0); }
104 | public static void AddNameFr(FlatBufferBuilder builder, StringOffset NameFrOffset) { builder.AddOffset(2, NameFrOffset.Value, 0); }
105 | public static void AddNameDe(FlatBufferBuilder builder, StringOffset NameDeOffset) { builder.AddOffset(3, NameDeOffset.Value, 0); }
106 | public static void AddNameJa(FlatBufferBuilder builder, StringOffset NameJaOffset) { builder.AddOffset(4, NameJaOffset.Value, 0); }
107 | public static Offset EndItem(FlatBufferBuilder builder) {
108 | int o = builder.EndTable();
109 | return new Offset(o);
110 | }
111 |
112 | public static VectorOffset CreateSortedVectorOfItem(FlatBufferBuilder builder, Offset
- [] offsets) {
113 | Array.Sort(offsets, (Offset
- o1, Offset
- o2) => builder.DataBuffer.GetUint(Table.__offset(4, o1.Value, builder.DataBuffer)).CompareTo(builder.DataBuffer.GetUint(Table.__offset(4, o2.Value, builder.DataBuffer))));
114 | return builder.CreateVectorOfTables(offsets);
115 | }
116 |
117 | public static Item? __lookup_by_key(int vectorLocation, uint key, ByteBuffer bb) {
118 | int span = bb.GetInt(vectorLocation - 4);
119 | int start = 0;
120 | while (span != 0) {
121 | int middle = span / 2;
122 | int tableOffset = Table.__indirect(vectorLocation + 4 * (start + middle), bb);
123 | int comp = bb.GetUint(Table.__offset(4, bb.Length - tableOffset, bb)).CompareTo(key);
124 | if (comp > 0) {
125 | span = middle;
126 | } else if (comp < 0) {
127 | middle++;
128 | start += middle;
129 | span -= middle;
130 | } else {
131 | return new Item().__assign(tableOffset, bb);
132 | }
133 | }
134 | return null;
135 | }
136 | };
137 |
138 |
139 | }
140 |
--------------------------------------------------------------------------------
/NetStone.GameData.Packs/NetStone.GameData.Packs.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp3.1
5 | enable
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/NetStone.GameData.Packs/PacksGameDataProvider.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 | using FFXIV;
4 | using FlatBuffers;
5 |
6 | namespace NetStone.GameData.Packs
7 | {
8 | public class PacksGameDataProvider : IGameDataProvider
9 | {
10 | private readonly ItemTable items;
11 |
12 | private PacksGameDataProvider(string path)
13 | {
14 | items = ItemTable.GetRootAsItemTable(LoadByteBuffer(Path.Combine(path, "item_table.bin")));
15 | }
16 |
17 | public NamedGameData? GetItem(string name)
18 | {
19 | var lower = name.ToLower().Replace("", string.Empty);
20 |
21 | for (var i = 0; i < items.ItemsLength; i++)
22 | {
23 | var item = items.Items(i)!.Value;
24 |
25 | if (lower.Equals(item.NameEn, StringComparison.InvariantCultureIgnoreCase)
26 | || lower.Equals(item.NameDe, StringComparison.InvariantCultureIgnoreCase)
27 | || lower.Equals(item.NameFr, StringComparison.InvariantCultureIgnoreCase)
28 | || lower.Equals(item.NameJa, StringComparison.InvariantCultureIgnoreCase))
29 | {
30 | return new NamedGameData
31 | {
32 | Info = new GameDataInfo
33 | {
34 | Key = item.Id,
35 | Name = name,
36 | },
37 |
38 | Name = new LanguageStrings
39 | {
40 | En = item.NameEn,
41 | De = item.NameDe,
42 | Fr = item.NameFr,
43 | Ja = item.NameJa,
44 | },
45 | };
46 | }
47 | }
48 |
49 | return null;
50 | }
51 |
52 | private ByteBuffer LoadByteBuffer(string file)
53 | {
54 | var bytes = File.ReadAllBytes(file);
55 | return new ByteBuffer(bytes);
56 | }
57 |
58 | public static PacksGameDataProvider Load(DirectoryInfo path) => new PacksGameDataProvider(path.FullName);
59 | }
60 | }
--------------------------------------------------------------------------------
/NetStone.Test/NetStone.Test.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net8.0
5 |
6 | false
7 | 10.0
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/NetStone.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 16
4 | VisualStudioVersion = 16.0.30717.126
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NetStone", "NetStone\NetStone.csproj", "{F1BA8D83-A58B-43EF-9B52-C6880CE8DBB6}"
7 | EndProject
8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NetStone.Test", "NetStone.Test\NetStone.Test.csproj", "{9753064B-BB14-46D8-9447-51A0B4AD7E02}"
9 | EndProject
10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FlatBuffers", "lib\flatbuffers\net\FlatBuffers\FlatBuffers.csproj", "{32F1B5DC-9E73-483C-B7FD-48EF97F2AA34}"
11 | EndProject
12 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NetStone.GameData.Packs", "NetStone.GameData.Packs\NetStone.GameData.Packs.csproj", "{D415EE52-ADB2-4B93-9B88-79D3A34A494E}"
13 | EndProject
14 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NetStone.GameData.Lumina", "NetStone.GameData.Lumina\NetStone.GameData.Lumina.csproj", "{6B3EB70B-127D-4B5B-83E2-E0660A0F684A}"
15 | EndProject
16 | Global
17 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
18 | Debug|Any CPU = Debug|Any CPU
19 | Release|Any CPU = Release|Any CPU
20 | EndGlobalSection
21 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
22 | {F1BA8D83-A58B-43EF-9B52-C6880CE8DBB6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
23 | {F1BA8D83-A58B-43EF-9B52-C6880CE8DBB6}.Debug|Any CPU.Build.0 = Debug|Any CPU
24 | {F1BA8D83-A58B-43EF-9B52-C6880CE8DBB6}.Release|Any CPU.ActiveCfg = Release|Any CPU
25 | {F1BA8D83-A58B-43EF-9B52-C6880CE8DBB6}.Release|Any CPU.Build.0 = Release|Any CPU
26 | {9753064B-BB14-46D8-9447-51A0B4AD7E02}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
27 | {9753064B-BB14-46D8-9447-51A0B4AD7E02}.Debug|Any CPU.Build.0 = Debug|Any CPU
28 | {9753064B-BB14-46D8-9447-51A0B4AD7E02}.Release|Any CPU.ActiveCfg = Release|Any CPU
29 | {9753064B-BB14-46D8-9447-51A0B4AD7E02}.Release|Any CPU.Build.0 = Release|Any CPU
30 | {32F1B5DC-9E73-483C-B7FD-48EF97F2AA34}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
31 | {32F1B5DC-9E73-483C-B7FD-48EF97F2AA34}.Debug|Any CPU.Build.0 = Debug|Any CPU
32 | {32F1B5DC-9E73-483C-B7FD-48EF97F2AA34}.Release|Any CPU.ActiveCfg = Release|Any CPU
33 | {32F1B5DC-9E73-483C-B7FD-48EF97F2AA34}.Release|Any CPU.Build.0 = Release|Any CPU
34 | {D415EE52-ADB2-4B93-9B88-79D3A34A494E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
35 | {D415EE52-ADB2-4B93-9B88-79D3A34A494E}.Debug|Any CPU.Build.0 = Debug|Any CPU
36 | {D415EE52-ADB2-4B93-9B88-79D3A34A494E}.Release|Any CPU.ActiveCfg = Release|Any CPU
37 | {D415EE52-ADB2-4B93-9B88-79D3A34A494E}.Release|Any CPU.Build.0 = Release|Any CPU
38 | {6B3EB70B-127D-4B5B-83E2-E0660A0F684A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
39 | {6B3EB70B-127D-4B5B-83E2-E0660A0F684A}.Debug|Any CPU.Build.0 = Debug|Any CPU
40 | {6B3EB70B-127D-4B5B-83E2-E0660A0F684A}.Release|Any CPU.ActiveCfg = Release|Any CPU
41 | {6B3EB70B-127D-4B5B-83E2-E0660A0F684A}.Release|Any CPU.Build.0 = Release|Any CPU
42 | EndGlobalSection
43 | GlobalSection(SolutionProperties) = preSolution
44 | HideSolutionNode = FALSE
45 | EndGlobalSection
46 | GlobalSection(ExtensibilityGlobals) = postSolution
47 | SolutionGuid = {BFEDBEEC-7831-4158-A1BF-B9FDCB780AFB}
48 | EndGlobalSection
49 | EndGlobal
50 |
--------------------------------------------------------------------------------
/NetStone/Changelog.md:
--------------------------------------------------------------------------------
1 | ## 1.4.1
2 | ### Behavioral changes
3 | - Exceptions from http requests are not caught and ignored anymore
4 | ### Fixes
5 | - Fixed FC search parameter for recruiting
6 | ### Contributors
7 | - Tawmy
8 | ## 1.4.0
9 | ### License
10 | - Switched to MIT license
11 | ### New Features
12 | - Added
13 | - LinkShells
14 | - Linkshell search
15 | - CWLS
16 | - CWLS search
17 | ## 1.3.1
18 | ### Bugfixes
19 | - Free Company search
20 | - Fixed queries with empty name
21 | - Fixed Active Times
22 | ### Contributors
23 | - Tawmy
24 | ## 1.3.0
25 | ### Breaking Changes
26 | - AttackMagicPotency in Character Attributes is now nullable
27 | - HealingMagicPotency in Character Attributes is now nullable
28 | ### New Features
29 | - Character Attributes
30 | - Added Craftsmanship
31 | - Added Control
32 | - Added Gathering
33 | - Added Perception
34 | - Free Company Member
35 | - Added Free Company Rank
36 | - Added Free Company Rank Icon
37 | - Gear
38 | - Added item level
39 | ### Contributors
40 | - Tawmy
41 | - Corielljacob
42 | ## 1.2.1
43 | ### New Features
44 | - Character
45 | - Added Bozja (credit to twobe7)
46 | - Added Eureka (credit to twobe7)
47 | ## 1.2.0
48 | ### Breaking Changes
49 | - ClassJobs are now non-nullable. Use IsUnlocked instead of a null check
50 | ### Fixes
51 | - Character achievements should now work as intended
52 | - Added new jobs (credit to Tawmy)
53 | ### New Features
54 | - Character
55 | - Added Tribe
56 | - Added Clan
57 | - Added Gender
58 | ## 1.1.2
59 | ### Fixes
60 | - FreeCompany
61 | - Fix exception when no ranking is present
62 | ## 1.1.1
63 | ### Fixes
64 | - Social Group
65 | - Exists works as intended now
66 | - Id returns null when the group does not exist
67 | ## 1.1.0
68 | ### New Features
69 | - Item HQ status
70 | - Game data updated for 6.4
71 | ### Fixes
72 | - Character
73 | - Level of active job
74 | - Materia
75 | - Job experience
76 | - Skill Speed
77 | - Achievement details
78 | - Free Company
79 | - Active State
80 | - Leveling focus
81 | ### Technical changes
82 | - Using C# built-in nullability (remove JetBrains annotations)
83 | ## 1.0.0
84 | Initial Release
--------------------------------------------------------------------------------
/NetStone/Constants.cs:
--------------------------------------------------------------------------------
1 | namespace NetStone;
2 |
3 | ///
4 | /// Contains constants used for initializing the Lodestone parser.
5 | ///
6 | public class Constants
7 | {
8 | ///
9 | /// Base URL for the Lodestone website.
10 | ///
11 | public const string LodestoneBase = "https://eu.finalfantasyxiv.com";
12 | }
--------------------------------------------------------------------------------
/NetStone/Definitions/.editorconfig:
--------------------------------------------------------------------------------
1 | #Ignore nullabilty for classes purely created by JSON deserialization
2 | [*.cs]
3 | dotnet_diagnostic.CS8618.severity = none
--------------------------------------------------------------------------------
/NetStone/Definitions/DefinitionsContainer.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Threading.Tasks;
3 | using NetStone.Definitions.Model;
4 | using NetStone.Definitions.Model.Character;
5 | using NetStone.Definitions.Model.CWLS;
6 | using NetStone.Definitions.Model.FreeCompany;
7 | using NetStone.Definitions.Model.Linkshell;
8 |
9 | namespace NetStone.Definitions;
10 |
11 | ///
12 | /// Class providing definitions(Selectors, paths) for parsing lodestone content.
13 | ///
14 | public abstract class DefinitionsContainer : IDisposable
15 | {
16 | #region Definitions
17 |
18 | ///
19 | /// Meta definitions
20 | /// Contains version, user-agents and Uris
21 | ///
22 | public MetaDefinition Meta { get; protected set; }
23 |
24 | ///
25 | /// General definitions for characters
26 | ///
27 | public CharacterDefinition Character { get; protected set; }
28 |
29 | ///
30 | /// Class information for characters
31 | ///
32 | public CharacterClassJobDefinition ClassJob { get; protected set; }
33 |
34 | ///
35 | /// Gear definitions for character
36 | ///
37 | public CharacterGearDefinition Gear { get; protected set; }
38 |
39 | ///
40 | /// Definitions for a character's attribute
41 | ///
42 | public CharacterAttributesDefinition Attributes { get; set; }
43 |
44 | ///
45 | /// Definitions for a character's achievements
46 | ///
47 | public CharacterAchievementDefinition Achievement { get; set; }
48 |
49 | ///
50 | /// Definitions for a character's mounts
51 | ///
52 | public CharacterCollectableDefinition Mount { get; set; }
53 |
54 | ///
55 | /// Definitions for a character's minions
56 | ///
57 | public CharacterCollectableDefinition Minion { get; set; }
58 |
59 | ///
60 | /// Definitions for Free Company
61 | ///
62 | public FreeCompanyDefinition FreeCompany { get; set; }
63 |
64 | ///
65 | /// Definitions for Free Company focus
66 | ///
67 | public FreeCompanyFocusDefinition FreeCompanyFocus { get; set; }
68 |
69 | ///
70 | /// Definitions for Free Company reputation
71 | ///
72 | public FreeCompanyReputationDefinition FreeCompanyReputation { get; set; }
73 |
74 | ///
75 | /// Definitions for Free Company member list
76 | ///
77 | public PagedDefinition FreeCompanyMembers { get; set; }
78 |
79 | ///
80 | /// Definitions for character search
81 | ///
82 | public PagedDefinition CharacterSearch { get; protected set; }
83 |
84 | ///
85 | /// Definitions for Free company search
86 | ///
87 | public PagedDefinition FreeCompanySearch { get; protected set; }
88 |
89 | ///
90 | /// Definitions for cross world link shells
91 | ///
92 | public CrossworldLinkshellDefinition CrossworldLinkshell { get; protected set; }
93 |
94 | ///
95 | /// Definitions for cross world link shell members
96 | ///
97 | public PagedDefinition CrossworldLinkshellMember { get; protected set; }
98 |
99 | ///
100 | /// Definitions for cross world link shell searches
101 | ///
102 | public PagedDefinition CrossworldLinkshellSearch { get; protected set; }
103 |
104 | ///
105 | /// Definitions for link shells
106 | ///
107 | public LinkshellDefinition Linkshell { get; protected set; }
108 |
109 | ///
110 | /// Definitions for link shell members
111 | ///
112 | public PagedDefinition LinkshellMember { get; protected set; }
113 |
114 | ///
115 | /// Definitions for link-shell searches
116 | ///
117 | public PagedDefinition LinkshellSearch { get; protected set; }
118 |
119 | #endregion
120 |
121 | ///
122 | /// Loads the definitions from repo
123 | ///
124 | /// Reload task
125 | public abstract Task Reload();
126 |
127 | ///
128 | public abstract void Dispose();
129 | }
--------------------------------------------------------------------------------
/NetStone/Definitions/DefinitionsPack.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Newtonsoft.Json;
3 |
4 | namespace NetStone.Definitions;
5 |
6 | ///
7 | /// Models the definition on how to extract information from the Lodestone HTML document
8 | ///
9 | public class DefinitionsPack
10 | {
11 | ///
12 | /// Hold a CSS selector to get the relevant html node from the DOM
13 | ///
14 | [JsonProperty("selector")]
15 | public string Selector { get; set; }
16 |
17 | ///
18 | /// A perl regex to extract the relevant information from the inner text of the relevant node
19 | ///
20 | [JsonProperty("regex")]
21 | public string? PerlBasedRegex { get; set; }
22 |
23 | ///
24 | /// C# usable regex based on
25 | ///
26 | public string? Regex => this.PerlBasedRegex?.Replace("(?P<", "(?<", StringComparison.InvariantCulture);
27 |
28 | //Never used
29 | //[JsonProperty("or")] public string Description { get; set; }
30 |
31 | ///
32 | /// HTML attribute that holds information. Only set if data is not in the inner text
33 | ///
34 | [JsonProperty("attribute")]
35 | public string? Attribute { get; set; }
36 | }
--------------------------------------------------------------------------------
/NetStone/Definitions/Model/CWLS/CrossworldLinkshellDefinition.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 |
3 | namespace NetStone.Definitions.Model.CWLS;
4 |
5 | ///
6 | /// Definitions for cross world link shell
7 | ///
8 | public class CrossworldLinkshellDefinition : IDefinition
9 | {
10 | ///
11 | /// Name
12 | ///
13 | [JsonProperty("NAME")]
14 | public DefinitionsPack Name { get; set; }
15 |
16 | ///
17 | /// Name
18 | ///
19 | [JsonProperty("DC")]
20 | public DefinitionsPack DataCenter { get; set; }
21 | }
--------------------------------------------------------------------------------
/NetStone/Definitions/Model/CWLS/CrossworldLinkshellMemberDefinition.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 |
3 | namespace NetStone.Definitions.Model.CWLS;
4 |
5 |
6 | ///
7 | ///
8 | ///
9 | public class CrossworldLinkshellMemberEntryDefinition : PagedEntryDefinition
10 | {
11 | ///
12 | /// Avatar
13 | ///
14 | [JsonProperty("AVATAR")] public DefinitionsPack Avatar { get; set; }
15 |
16 | ///
17 | /// ID
18 | ///
19 | [JsonProperty("ID")] public DefinitionsPack Id { get; set; }
20 |
21 | ///
22 | /// Name
23 | ///
24 | [JsonProperty("NAME")] public DefinitionsPack Name { get; set; }
25 |
26 | ///
27 | /// Rank
28 | ///
29 | [JsonProperty("RANK")] public DefinitionsPack Rank { get; set; }
30 |
31 | ///
32 | /// Rank Icon
33 | ///
34 | [JsonProperty("RANK_ICON")] public DefinitionsPack RankIcon { get; set; }
35 |
36 | ///
37 | /// Linkshell rank
38 | ///
39 | [JsonProperty("LINKSHELL_RANK")] public DefinitionsPack LinkshellRank { get; set; }
40 |
41 | ///
42 | /// Linkshell rank Icon
43 | ///
44 | [JsonProperty("LINKSHELL_RANK_ICON")] public DefinitionsPack LinkshellRankIcon { get; set; }
45 |
46 | ///
47 | /// Server
48 | ///
49 | [JsonProperty("SERVER")] public DefinitionsPack Server { get; set; }
50 | }
--------------------------------------------------------------------------------
/NetStone/Definitions/Model/CWLS/CrossworldLinkshellSearchDefinition.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 |
3 | namespace NetStone.Definitions.Model.CWLS;
4 | ///
5 | /// Definition container for one Cross World Link Shell search result entry
6 | ///
7 | public class CrossworldLinkshellSearchEntryDefinition : PagedEntryDefinition
8 | {
9 | ///
10 | /// ID
11 | ///
12 | [JsonProperty("ID")] public DefinitionsPack Id { get; set; }
13 |
14 | ///
15 | /// Name
16 | ///
17 | [JsonProperty("NAME")] public DefinitionsPack Name { get; set; }
18 |
19 | ///
20 | /// Rank
21 | ///
22 | [JsonProperty("DC")] public DefinitionsPack Dc { get; set; }
23 |
24 | ///
25 | /// Rank Icon
26 | ///
27 | [JsonProperty("ACTIVE_MEMBERS")] public DefinitionsPack ActiveMembers { get; set; }
28 | }
--------------------------------------------------------------------------------
/NetStone/Definitions/Model/Character/CharacterAchievementDefinition.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 |
3 | namespace NetStone.Definitions.Model.Character;
4 |
5 | ///
6 | /// Models the definition of the achievement list
7 | ///
8 | public class CharacterAchievementDefinition : PagedDefinition
9 | {
10 | ///
11 | /// Total number of achievements earned by this character
12 | ///
13 | [JsonProperty("TOTAL_ACHIEVEMENTS")]
14 | public DefinitionsPack TotalAchievements { get; set; }
15 |
16 | ///
17 | /// Total achievement points earned by this character
18 | ///
19 | [JsonProperty("ACHIEVEMENT_POINTS")]
20 | public DefinitionsPack AchievementPoints { get; set; }
21 |
22 | ///
23 | /// Full text displayed for this achievement
24 | ///
25 | [JsonProperty("ACTIVITY_DESCRIPTION")]
26 | public DefinitionsPack ActivityDescription { get; set; }
27 | }
28 | ///
29 | /// Models the definition of one achievement entry for a character
30 | ///
31 | public class CharacterAchievementEntryDefinition : PagedEntryDefinition
32 | {
33 | ///
34 | /// Achievement name
35 | ///
36 | [JsonProperty("NAME")]
37 | public DefinitionsPack Name { get; set; }
38 |
39 | ///
40 | /// Id of this achievement
41 | ///
42 | [JsonProperty("ID")]
43 | public DefinitionsPack Id { get; set; }
44 |
45 | ///
46 | /// Time when this achievement was earned
47 | ///
48 | [JsonProperty("TIME")]
49 | public DefinitionsPack Time { get; set; }
50 | }
--------------------------------------------------------------------------------
/NetStone/Definitions/Model/Character/CharacterAttributesDefinition.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 |
3 | namespace NetStone.Definitions.Model.Character;
4 |
5 | ///
6 | /// Node definitions for a character's attributes
7 | ///
8 | public class CharacterAttributesDefinition : IDefinition
9 | {
10 | ///
11 | /// Strength
12 | ///
13 | [JsonProperty("STRENGTH")]
14 | public DefinitionsPack Strength { get; set; }
15 |
16 | ///
17 | /// Dexterity
18 | ///
19 | [JsonProperty("DEXTERITY")]
20 | public DefinitionsPack Dexterity { get; set; }
21 |
22 | ///
23 | /// Vitality
24 | ///
25 | [JsonProperty("VITALITY")]
26 | public DefinitionsPack Vitality { get; set; }
27 |
28 | ///
29 | /// Intelligence
30 | ///
31 | [JsonProperty("INTELLIGENCE")]
32 | public DefinitionsPack Intelligence { get; set; }
33 |
34 | ///
35 | /// Mind
36 | ///
37 | [JsonProperty("MIND")]
38 | public DefinitionsPack Mind { get; set; }
39 |
40 | ///
41 | /// Critical Hit
42 | ///
43 | [JsonProperty("CRITICAL_HIT_RATE")]
44 | public DefinitionsPack CriticalHitRate { get; set; }
45 |
46 | ///
47 | /// Determination
48 | ///
49 | [JsonProperty("DETERMINATION")]
50 | public DefinitionsPack Determination { get; set; }
51 |
52 | ///
53 | /// Direct Hit
54 | ///
55 | [JsonProperty("DIRECT_HIT_RATE")]
56 | public DefinitionsPack DirectHitRate { get; set; }
57 |
58 | ///
59 | /// Defense
60 | ///
61 | [JsonProperty("DEFENSE")]
62 | public DefinitionsPack Defense { get; set; }
63 |
64 | ///
65 | /// Magic Defense
66 | ///
67 | [JsonProperty("MAGIC_DEFENSE")]
68 | public DefinitionsPack MagicDefense { get; set; }
69 |
70 | ///
71 | /// Attack Power
72 | ///
73 | [JsonProperty("ATTACK_POWER")]
74 | public DefinitionsPack AttackPower { get; set; }
75 |
76 | ///
77 | /// Skill Speed
78 | ///
79 | [JsonProperty("SKILL_SPEED")]
80 | public DefinitionsPack SkillSpeed { get; set; }
81 |
82 | ///
83 | /// Attack Magic Potency
84 | ///
85 | [JsonProperty("ATTACK_MAGIC_POTENCY")]
86 | public DefinitionsPack AttackMagicPotency { get; set; }
87 |
88 | ///
89 | /// Healing Magic Potency
90 | ///
91 | [JsonProperty("HEALING_MAGIC_POTENCY")]
92 | public DefinitionsPack HealingMagicPotency { get; set; }
93 |
94 | ///
95 | /// Spell Speed
96 | ///
97 | [JsonProperty("SPELL_SPEED")]
98 | public DefinitionsPack SpellSpeed { get; set; }
99 |
100 | ///
101 | /// Tenacity
102 | ///
103 | [JsonProperty("TENACITY")]
104 | public DefinitionsPack Tenacity { get; set; }
105 |
106 | ///
107 | /// Piety
108 | ///
109 | [JsonProperty("PIETY")]
110 | public DefinitionsPack Piety { get; set; }
111 |
112 | ///
113 | /// Hit Points
114 | ///
115 | [JsonProperty("HP")]
116 | public DefinitionsPack Hp { get; set; }
117 |
118 | ///
119 | /// MP, GP or CP depending on Job
120 | ///
121 | [JsonProperty("MP_GP_CP")]
122 | public DefinitionsPack MpGpCp { get; set; }
123 |
124 | ///
125 | /// Name of
126 | ///
127 | [JsonProperty("MP_GP_CP_PARAMETER_NAME")]
128 | public DefinitionsPack MpGpCpParameterName { get; set; }
129 | }
--------------------------------------------------------------------------------
/NetStone/Definitions/Model/Character/CharacterCollectableDefinition.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 |
3 | namespace NetStone.Definitions.Model.Character;
4 |
5 | ///
6 | /// General class for a category of collectables
7 | ///
8 | public interface CharacterCollectableDefinition : IDefinition
9 | {
10 | ///
11 | /// Get node definition for and entry
12 | ///
13 | /// Node definition
14 | public CollectableNodeDefinition GetDefinitions();
15 | }
16 |
17 | ///
18 | /// Definition pack for a character's mounts
19 | ///
20 | public class CharacterMountDefinition : CharacterCollectableDefinition
21 | {
22 | ///
23 | /// Node definition for mounts
24 | ///
25 | [JsonProperty("MOUNTS")]
26 | public CollectableNodeDefinition Mounts { get; set; }
27 |
28 | ///
29 | public CollectableNodeDefinition GetDefinitions() => this.Mounts;
30 | }
31 |
32 | ///
33 | /// Definition pack for a character's minions
34 | ///
35 | public class CharacterMinionDefinition : CharacterCollectableDefinition
36 | {
37 | ///
38 | /// Noe definition for minions
39 | ///
40 | [JsonProperty("MINIONS")]
41 | public CollectableNodeDefinition Minions { get; set; }
42 |
43 | ///
44 | public CollectableNodeDefinition GetDefinitions() => this.Minions;
45 | }
46 |
47 | ///
48 | /// General definition for a collectable
49 | ///
50 | public class CollectableNodeDefinition
51 | {
52 | ///
53 | /// Root node of collectable entry
54 | ///
55 | [JsonProperty("ROOT")]
56 | public DefinitionsPack Root { get; set; }
57 |
58 | ///
59 | /// Name
60 | ///
61 | [JsonProperty("NAME")]
62 | public DefinitionsPack Name { get; set; }
63 | }
--------------------------------------------------------------------------------
/NetStone/Definitions/Model/Character/CharacterDefinition.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 |
3 | namespace NetStone.Definitions.Model.Character;
4 |
5 | ///
6 | /// Definitions for free company of character
7 | ///
8 | public class CharacterFreeCompany : ICharacterSocialGroupDefinition
9 | {
10 | ///
11 | [JsonProperty("NAME")]
12 | public DefinitionsPack Name { get; set; }
13 |
14 | ///
15 | [JsonProperty("ICON_LAYERS")]
16 | public IconLayersDefinition IconLayers { get; set; }
17 | }
18 |
19 | ///
20 | /// Definitions for PvP team of character
21 | ///
22 | public class CharacterPvPTeam : ICharacterSocialGroupDefinition
23 | {
24 | ///
25 | [JsonProperty("NAME")]
26 | public DefinitionsPack Name { get; set; }
27 |
28 | ///
29 | [JsonProperty("ICON_LAYERS")]
30 | public IconLayersDefinition IconLayers { get; set; }
31 | }
32 |
33 | ///
34 | /// General definition of a social group
35 | ///
36 | public interface ICharacterSocialGroupDefinition : IDefinition
37 | {
38 | ///
39 | /// Definition for the name of the group
40 | ///
41 | DefinitionsPack Name { get; set; }
42 |
43 | ///
44 | /// Definition of Icon Layers
45 | ///
46 | IconLayersDefinition IconLayers { get; set; }
47 | }
48 |
49 | ///
50 | /// Generic definition for icon and name combination
51 | ///
52 | public class NameIconDefinition : IDefinition
53 | {
54 | ///
55 | /// Name
56 | ///
57 | [JsonProperty("NAME")]
58 | public DefinitionsPack Name { get; set; }
59 |
60 | ///
61 | /// Icon
62 | ///
63 | [JsonProperty("ICON")]
64 | public DefinitionsPack Icon { get; set; }
65 | }
66 |
67 | ///
68 | /// Set of definition packs for character profile
69 | ///
70 | public class CharacterDefinition : IDefinition
71 | {
72 | ///
73 | /// Currently active class/job
74 | ///
75 | [JsonProperty("ACTIVE_CLASSJOB")]
76 | public DefinitionsPack ActiveClassJob { get; set; }
77 |
78 | ///
79 | /// Level of current class/job
80 | ///
81 | [JsonProperty("ACTIVE_CLASSJOB_LEVEL")]
82 | public DefinitionsPack ActiveClassJobLevel { get; set; }
83 |
84 | ///
85 | /// Characters avatar picture
86 | ///
87 | [JsonProperty("AVATAR")]
88 | public DefinitionsPack Avatar { get; set; }
89 |
90 | ///
91 | /// Players description for this character
92 | ///
93 | [JsonProperty("BIO")]
94 | public DefinitionsPack Bio { get; set; }
95 |
96 | ///
97 | /// Free Company of this character
98 | ///
99 | [JsonProperty("FREE_COMPANY")]
100 | public CharacterFreeCompany FreeCompany { get; set; }
101 |
102 | ///
103 | /// Grand company
104 | ///
105 | [JsonProperty("GRAND_COMPANY")]
106 | public DefinitionsPack GrandCompany { get; set; }
107 |
108 | ///
109 | /// Deity
110 | ///
111 | [JsonProperty("GUARDIAN_DEITY")]
112 | public NameIconDefinition GuardianDeity { get; set; }
113 |
114 | ///
115 | /// Name
116 | ///
117 | [JsonProperty("NAME")]
118 | public DefinitionsPack Name { get; set; }
119 |
120 | ///
121 | /// Nameday (Birthday)
122 | ///
123 | [JsonProperty("NAMEDAY")]
124 | public DefinitionsPack Nameday { get; set; }
125 |
126 | ///
127 | /// Image of full character
128 | ///
129 | [JsonProperty("PORTRAIT")]
130 | public DefinitionsPack Portrait { get; set; }
131 |
132 | ///
133 | /// PvP Team
134 | ///
135 | [JsonProperty("PVP_TEAM")]
136 | public CharacterPvPTeam PvPTeam { get; set; }
137 |
138 | ///
139 | /// Race, Clan and Gender of the character
140 | ///
141 | [JsonProperty("RACE_CLAN_GENDER")]
142 | public DefinitionsPack RaceClanGender { get; set; }
143 |
144 | ///
145 | /// Homeworld of the character
146 | ///
147 | [JsonProperty("SERVER")]
148 | public DefinitionsPack Server { get; set; }
149 |
150 | ///
151 | /// Title
152 | ///
153 | [JsonProperty("TITLE")]
154 | public DefinitionsPack Title { get; set; }
155 |
156 | ///
157 | /// City-State affiliation
158 | ///
159 | [JsonProperty("TOWN")]
160 | public NameIconDefinition Town { get; set; }
161 | }
--------------------------------------------------------------------------------
/NetStone/Definitions/Model/Character/CharacterGearDefinition.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 |
3 | namespace NetStone.Definitions.Model.Character;
4 |
5 | ///
6 | /// Definitions for a slot of gear in character profile
7 | ///
8 | public class GearEntryDefinition
9 | {
10 | ///
11 | /// Name of the item
12 | ///
13 | [JsonProperty("NAME")]
14 | public DefinitionsPack Name { get; set; }
15 |
16 | ///
17 | /// Link to Eorzea Database for item
18 | ///
19 | [JsonProperty("DB_LINK")]
20 | public DefinitionsPack DbLink { get; set; }
21 |
22 | ///
23 | /// Name of glamour
24 | ///
25 | [JsonProperty("MIRAGE_NAME")]
26 | public DefinitionsPack MirageName { get; set; }
27 |
28 | ///
29 | /// Link to Eorzea Database for glamour item
30 | ///
31 | [JsonProperty("MIRAGE_DB_LINK")]
32 | public DefinitionsPack MirageDbLink { get; set; }
33 |
34 | ///
35 | /// Die of the item
36 | ///
37 | [JsonProperty("STAIN")]
38 | public DefinitionsPack Stain { get; set; }
39 |
40 | ///
41 | /// Materia Slot 1
42 | ///
43 | [JsonProperty("MATERIA_1")]
44 | public DefinitionsPack Materia1 { get; set; }
45 |
46 | ///
47 | /// Materia Slot 2
48 | ///
49 | [JsonProperty("MATERIA_2")]
50 | public DefinitionsPack Materia2 { get; set; }
51 |
52 | ///
53 | /// Materia Slot 3
54 | ///
55 | [JsonProperty("MATERIA_3")]
56 | public DefinitionsPack Materia3 { get; set; }
57 |
58 | ///
59 | /// Materia Slot 4
60 | ///
61 | [JsonProperty("MATERIA_4")]
62 | public DefinitionsPack Materia4 { get; set; }
63 |
64 | ///
65 | /// Materia Slot 5
66 | ///
67 | [JsonProperty("MATERIA_5")]
68 | public DefinitionsPack Materia5 { get; set; }
69 |
70 | ///
71 | /// Name of creator/crafter of this item (if applicable)
72 | ///
73 | [JsonProperty("CREATOR_NAME")]
74 | public DefinitionsPack CreatorName { get; set; }
75 |
76 | ///
77 | /// Item level of the item
78 | ///
79 | [JsonProperty("ITEM_LEVEL")]
80 | public DefinitionsPack ItemLevel { get; set; }
81 | }
82 |
83 | ///
84 | /// Definition for Soul Crystal slot
85 | ///
86 | public class SoulcrystalEntryDefinition
87 | {
88 | ///
89 | /// Name of the item
90 | ///
91 | [JsonProperty("NAME")]
92 | public DefinitionsPack Name { get; set; }
93 | }
94 |
95 | ///
96 | /// Definition for all gear of the character
97 | ///
98 | public class CharacterGearDefinition : IDefinition
99 | {
100 | ///
101 | /// Main hand weapon
102 | ///
103 | [JsonProperty("MAINHAND")]
104 | public GearEntryDefinition Mainhand { get; set; }
105 |
106 | ///
107 | /// Off hand weapon
108 | ///
109 | [JsonProperty("OFFHAND")]
110 | public GearEntryDefinition Offhand { get; set; }
111 |
112 | ///
113 | /// Head piece
114 | ///
115 | [JsonProperty("HEAD")]
116 | public GearEntryDefinition Head { get; set; }
117 |
118 | ///
119 | /// Chest piece
120 | ///
121 | [JsonProperty("BODY")]
122 | public GearEntryDefinition Body { get; set; }
123 |
124 | ///
125 | /// Hand piece
126 | ///
127 | [JsonProperty("HANDS")]
128 | public GearEntryDefinition Hands { get; set; }
129 |
130 | ///
131 | /// Waist
132 | ///
133 | [JsonProperty("WAIST")]
134 | public GearEntryDefinition Waist { get; set; }
135 |
136 | ///
137 | /// Legs
138 | ///
139 | [JsonProperty("LEGS")]
140 | public GearEntryDefinition Legs { get; set; }
141 |
142 | ///
143 | /// Feet
144 | ///
145 | [JsonProperty("FEET")]
146 | public GearEntryDefinition Feet { get; set; }
147 |
148 | ///
149 | /// Earrings
150 | ///
151 | [JsonProperty("EARRINGS")]
152 | public GearEntryDefinition Earrings { get; set; }
153 |
154 | ///
155 | /// Necklace
156 | ///
157 | [JsonProperty("NECKLACE")]
158 | public GearEntryDefinition Necklace { get; set; }
159 |
160 | ///
161 | /// Braccelets
162 | ///
163 | [JsonProperty("BRACELETS")]
164 | public GearEntryDefinition Bracelets { get; set; }
165 |
166 | ///
167 | /// Right ring
168 | ///
169 | [JsonProperty("RING1")]
170 | public GearEntryDefinition Ring1 { get; set; }
171 |
172 | ///
173 | /// Left ring
174 | ///
175 | [JsonProperty("RING2")]
176 | public GearEntryDefinition Ring2 { get; set; }
177 |
178 | ///
179 | /// Soul Crystal
180 | ///
181 | [JsonProperty("SOULCRYSTAL")]
182 | public SoulcrystalEntryDefinition Soulcrystal { get; set; }
183 | }
--------------------------------------------------------------------------------
/NetStone/Definitions/Model/Character/CharacterSearchDefinition.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 |
3 | namespace NetStone.Definitions.Model.Character;
4 |
5 | ///
6 | /// Definition pack for character search results
7 | ///
8 | public class CharacterSearchEntryDefinition : PagedEntryDefinition
9 | {
10 | ///
11 | /// Avatar of character
12 | ///
13 | [JsonProperty("AVATAR")]
14 | public DefinitionsPack Avatar { get; set; }
15 |
16 | ///
17 | /// Lodestone Id
18 | ///
19 | [JsonProperty("ID")]
20 | public DefinitionsPack Id { get; set; }
21 |
22 | ///
23 | /// Language
24 | ///
25 | [JsonProperty("LANG")]
26 | public DefinitionsPack Lang { get; set; }
27 |
28 | ///
29 | /// Name
30 | ///
31 | [JsonProperty("NAME")]
32 | public DefinitionsPack Name { get; set; }
33 |
34 | ///
35 | /// Grand Company rank
36 | ///
37 | [JsonProperty("RANK")]
38 | public DefinitionsPack Rank { get; set; }
39 |
40 | ///
41 | /// Grand Company rank icon
42 | ///
43 | [JsonProperty("RANK_ICON")]
44 | public DefinitionsPack RankIcon { get; set; }
45 |
46 | ///
47 | /// Homeworld
48 | ///
49 | [JsonProperty("SERVER")]
50 | public DefinitionsPack Server { get; set; }
51 | }
--------------------------------------------------------------------------------
/NetStone/Definitions/Model/FreeCompany/FreeCompanyDefinition.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 |
3 | namespace NetStone.Definitions.Model.FreeCompany;
4 |
5 | ///
6 | /// Definitions for FC estate
7 | ///
8 | public class EstateDefinition : IDefinition
9 | {
10 | ///
11 | /// Definition for empty estate
12 | ///
13 | [JsonProperty("NO_ESTATE")]
14 | public DefinitionsPack NoEstate { get; set; }
15 |
16 | ///
17 | /// Greeting
18 | ///
19 | [JsonProperty("GREETING")]
20 | public DefinitionsPack Greeting { get; set; }
21 |
22 | ///
23 | /// Name
24 | ///
25 | [JsonProperty("NAME")]
26 | public DefinitionsPack Name { get; set; }
27 |
28 | ///
29 | /// Plot
30 | ///
31 | [JsonProperty("PLOT")]
32 | public DefinitionsPack Plot { get; set; }
33 | }
34 |
35 | ///
36 | /// Ranking definitions
37 | ///
38 | public class Ranking
39 | {
40 | ///
41 | /// Weekly ranking
42 | ///
43 | [JsonProperty("WEEKLY")]
44 | public DefinitionsPack Weekly { get; set; }
45 |
46 | ///
47 | /// Monthly ranking
48 | ///
49 | [JsonProperty("MONTHLY")]
50 | public DefinitionsPack Monthly { get; set; }
51 | }
52 |
53 | ///
54 | /// Definitions for free company profile
55 | ///
56 | public class FreeCompanyDefinition : IDefinition
57 | {
58 | ///
59 | /// Is Active
60 | ///
61 | [JsonProperty("ACTIVE_STATE")]
62 | public DefinitionsPack Activestate { get; set; }
63 |
64 | ///
65 | /// Active member count
66 | ///
67 | [JsonProperty("ACTIVE_MEMBER_COUNT")]
68 | public DefinitionsPack ActiveMemberCount { get; set; }
69 |
70 | ///
71 | /// Layers of the crest
72 | ///
73 | [JsonProperty("CREST_LAYERS")]
74 | public IconLayersDefinition CrestLayers { get; set; }
75 |
76 | ///
77 | /// Information about estate
78 | ///
79 | [JsonProperty("ESTATE")]
80 | public EstateDefinition EstateDefinition { get; set; }
81 |
82 | ///
83 | /// Foundation date
84 | ///
85 | [JsonProperty("FORMED")]
86 | public DefinitionsPack Formed { get; set; }
87 |
88 | ///
89 | /// Grand company
90 | ///
91 | [JsonProperty("GRAND_COMPANY")]
92 | public DefinitionsPack GrandCompany { get; set; }
93 |
94 | ///
95 | /// Id
96 | ///
97 | [JsonProperty("ID")]
98 | public DefinitionsPack Id { get; set; }
99 |
100 | ///
101 | /// Name
102 | ///
103 | [JsonProperty("NAME")]
104 | public DefinitionsPack Name { get; set; }
105 |
106 | ///
107 | /// Rank
108 | ///
109 | [JsonProperty("RANK")]
110 | public DefinitionsPack Rank { get; set; }
111 |
112 | ///
113 | /// Rankings
114 | ///
115 | [JsonProperty("RANKING")]
116 | public Ranking Ranking { get; set; }
117 |
118 | ///
119 | /// Recruitment info
120 | ///
121 | [JsonProperty("RECRUITMENT")]
122 | public DefinitionsPack Recruitment { get; set; }
123 |
124 | ///
125 | /// World
126 | ///
127 | [JsonProperty("SERVER")]
128 | public DefinitionsPack Server { get; set; }
129 |
130 | ///
131 | /// Slogan
132 | ///
133 | [JsonProperty("SLOGAN")]
134 | public DefinitionsPack Slogan { get; set; }
135 |
136 | ///
137 | /// Tags
138 | ///
139 | [JsonProperty("TAG")]
140 | public DefinitionsPack Tag { get; set; }
141 | }
--------------------------------------------------------------------------------
/NetStone/Definitions/Model/FreeCompany/FreeCompanyFocusDefinition.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 |
3 | namespace NetStone.Definitions.Model.FreeCompany;
4 |
5 | ///
6 | /// Definition for one type of FC foc
7 | /// us
8 | ///
9 | public class FreeCompanyFocusEntryDefinition : IDefinition
10 | {
11 | ///
12 | /// Name of type
13 | ///
14 | [JsonProperty("NAME")]
15 | public DefinitionsPack NAME { get; set; }
16 |
17 | ///
18 | /// Icon for type
19 | ///
20 | [JsonProperty("ICON")]
21 | public DefinitionsPack ICON { get; set; }
22 |
23 | ///
24 | /// Status (if company focuses on this)
25 | ///
26 | [JsonProperty("STATUS")]
27 | public DefinitionsPack STATUS { get; set; }
28 | }
29 |
30 | ///
31 | /// Definition container for all FC focus types
32 | ///
33 | public class FreeCompanyFocusDefinition : IDefinition
34 | {
35 | ///
36 | /// No focus specified
37 | ///
38 | [JsonProperty("NOT_SPECIFIED")]
39 | public DefinitionsPack NOTSPECIFIED { get; set; }
40 |
41 | ///
42 | /// Role play
43 | ///
44 | [JsonProperty("RP")]
45 | public FreeCompanyFocusEntryDefinition RolePlay { get; set; }
46 |
47 | ///
48 | /// Leveling
49 | ///
50 | [JsonProperty("LEVELING")]
51 | public FreeCompanyFocusEntryDefinition Leveling { get; set; }
52 |
53 | ///
54 | /// Casual
55 | ///
56 | [JsonProperty("CASUAL")]
57 | public FreeCompanyFocusEntryDefinition Casual { get; set; }
58 |
59 | ///
60 | /// Hardcore
61 | ///
62 | [JsonProperty("HARDCORE")]
63 | public FreeCompanyFocusEntryDefinition Hardcore { get; set; }
64 |
65 | ///
66 | /// Dungeons
67 | ///
68 | [JsonProperty("DUNGEONS")]
69 | public FreeCompanyFocusEntryDefinition Dungeons { get; set; }
70 |
71 | ///
72 | /// Guild hests
73 | ///
74 | [JsonProperty("GUILDHESTS")]
75 | public FreeCompanyFocusEntryDefinition Guildhests { get; set; }
76 |
77 | ///
78 | /// Trials
79 | ///
80 | [JsonProperty("TRIALS")]
81 | public FreeCompanyFocusEntryDefinition Trials { get; set; }
82 |
83 | ///
84 | /// Raids
85 | ///
86 | [JsonProperty("RAIDS")]
87 | public FreeCompanyFocusEntryDefinition Raids { get; set; }
88 |
89 | ///
90 | /// PvP
91 | ///
92 | [JsonProperty("PVP")]
93 | public FreeCompanyFocusEntryDefinition PvP { get; set; }
94 | }
--------------------------------------------------------------------------------
/NetStone/Definitions/Model/FreeCompany/FreeCompanyMembersEntryDefinition.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 |
3 | namespace NetStone.Definitions.Model.FreeCompany;
4 |
5 | ///
6 | /// Definition for one FC member
7 | ///
8 | public class FreeCompanyMembersEntryDefinition : PagedEntryDefinition
9 | {
10 | ///
11 | /// Avatar of member character
12 | ///
13 | [JsonProperty("AVATAR")]
14 | public DefinitionsPack Avatar { get; set; }
15 |
16 | ///
17 | /// ID of character
18 | ///
19 | [JsonProperty("ID")]
20 | public DefinitionsPack Id { get; set; }
21 |
22 | ///
23 | /// Name of character
24 | ///
25 | [JsonProperty("NAME")]
26 | public DefinitionsPack Name { get; set; }
27 |
28 | ///
29 | /// Grand company rank
30 | ///
31 | [JsonProperty("RANK")]
32 | public DefinitionsPack Rank { get; set; }
33 |
34 | ///
35 | /// GC rank icon
36 | ///
37 | [JsonProperty("RANK_ICON")]
38 | public DefinitionsPack RankIcon { get; set; }
39 |
40 | ///
41 | /// Free company rank
42 | ///
43 | [JsonProperty("FC_RANK")]
44 | public DefinitionsPack FreeCompanyRank { get; set; }
45 |
46 | ///
47 | /// FC rank icon
48 | ///
49 | [JsonProperty("FC_RANK_ICON")]
50 | public DefinitionsPack FreeCompanyRankIcon { get; set; }
51 |
52 | ///
53 | /// Homeworld
54 | ///
55 | [JsonProperty("SERVER")]
56 | public DefinitionsPack Server { get; set; }
57 | }
--------------------------------------------------------------------------------
/NetStone/Definitions/Model/FreeCompany/FreeCompanyReputationDefinition.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 |
3 | namespace NetStone.Definitions.Model.FreeCompany;
4 |
5 | ///
6 | /// Definition for reputation of FC with GC
7 | ///
8 | public class FreeCompanyReputationEntryDefinition : IDefinition
9 | {
10 | ///
11 | /// Name of the Grand Company
12 | ///
13 | [JsonProperty("NAME")]
14 | public DefinitionsPack Name { get; set; }
15 |
16 | ///
17 | /// Progress to next rank
18 | ///
19 | [JsonProperty("PROGRESS")]
20 | public DefinitionsPack Progress { get; set; }
21 |
22 | ///
23 | /// Current Rank
24 | ///
25 | [JsonProperty("RANK")]
26 | public DefinitionsPack Rank { get; set; }
27 | }
28 |
29 | ///
30 | /// Definition container for all reputations of a FC
31 | ///
32 | public class FreeCompanyReputationDefinition : IDefinition
33 | {
34 | ///
35 | /// Maelstrom
36 | ///
37 | [JsonProperty("MAELSTROM")]
38 | public FreeCompanyReputationEntryDefinition Maelstrom { get; set; }
39 |
40 | ///
41 | /// Order of the Twin Adder
42 | ///
43 | [JsonProperty("ADDERS")]
44 | public FreeCompanyReputationEntryDefinition Adders { get; set; }
45 |
46 | ///
47 | /// Immortal Flames
48 | ///
49 | [JsonProperty("FLAMES")]
50 | public FreeCompanyReputationEntryDefinition Flames { get; set; }
51 | }
--------------------------------------------------------------------------------
/NetStone/Definitions/Model/FreeCompany/FreeCompanySearchDefinition.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 |
3 | namespace NetStone.Definitions.Model.FreeCompany;
4 |
5 | ///
6 | /// Definition container for one Free Company search result entry
7 | ///
8 | public class FreeCompanySearchEntryDefinition : PagedEntryDefinition
9 | {
10 | ///
11 | /// Crest layers
12 | ///
13 | [JsonProperty("CREST_LAYERS")]
14 | public IconLayersDefinition CrestLayers { get; set; }
15 |
16 | ///
17 | /// FC Id
18 | ///
19 | [JsonProperty("ID")]
20 | public DefinitionsPack Id { get; set; }
21 |
22 | ///
23 | /// Grand Company
24 | ///
25 | [JsonProperty("GRAND_COMPANY")]
26 | public DefinitionsPack GrandCompany { get; set; }
27 |
28 | ///
29 | /// Name
30 | ///
31 | [JsonProperty("NAME")]
32 | public DefinitionsPack Name { get; set; }
33 |
34 | ///
35 | /// World
36 | ///
37 | [JsonProperty("SERVER")]
38 | public DefinitionsPack Server { get; set; }
39 |
40 | ///
41 | /// FC active status
42 | ///
43 | [JsonProperty("ACTIVE")]
44 | public DefinitionsPack Active { get; set; }
45 |
46 | ///
47 | /// Active member count
48 | ///
49 | [JsonProperty("ACTIVE_MEMBERS")]
50 | public DefinitionsPack ActiveMembers { get; set; }
51 |
52 | ///
53 | /// Recruitment status
54 | ///
55 | [JsonProperty("RECRUITMENT_OPEN")]
56 | public DefinitionsPack RecruitmentOpen { get; set; }
57 |
58 | ///
59 | /// Estate state
60 | ///
61 | [JsonProperty("ESTATE_BUILT")]
62 | public DefinitionsPack EstateBuilt { get; set; }
63 |
64 | ///
65 | /// Formation date
66 | ///
67 | [JsonProperty("FORMED")]
68 | public DefinitionsPack Formed { get; set; }
69 | }
--------------------------------------------------------------------------------
/NetStone/Definitions/Model/IDefinition.cs:
--------------------------------------------------------------------------------
1 | namespace NetStone.Definitions.Model;
2 |
3 | ///
4 | /// Interface for all node definitions
5 | ///
6 | public interface IDefinition
7 | {
8 | }
--------------------------------------------------------------------------------
/NetStone/Definitions/Model/IconLayersDefinition.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 |
3 | namespace NetStone.Definitions.Model;
4 |
5 | ///
6 | /// Definition for an icon with multiple layers
7 | ///
8 | public class IconLayersDefinition : IDefinition
9 | {
10 | ///
11 | /// Bottom layer
12 | ///
13 | [JsonProperty("BOTTOM")]
14 | public DefinitionsPack Bottom { get; set; }
15 |
16 | ///
17 | /// Middle layer
18 | ///
19 | [JsonProperty("MIDDLE")]
20 | public DefinitionsPack Middle { get; set; }
21 |
22 | ///
23 | /// Top layer
24 | ///
25 | [JsonProperty("TOP")]
26 | public DefinitionsPack Top { get; set; }
27 | }
--------------------------------------------------------------------------------
/NetStone/Definitions/Model/Linkshell/LinkshellDefinition.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 |
3 | namespace NetStone.Definitions.Model.Linkshell;
4 |
5 | ///
6 | /// Definitions for link shell
7 | ///
8 | public class LinkshellDefinition : IDefinition
9 | {
10 | ///
11 | /// Name
12 | ///
13 | [JsonProperty("NAME")]
14 | public DefinitionsPack Name { get; set; }
15 | }
--------------------------------------------------------------------------------
/NetStone/Definitions/Model/Linkshell/LinkshellMemberDefinition.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 |
3 | namespace NetStone.Definitions.Model.Linkshell;
4 |
5 | ///
6 | /// Definition for one entry of the linkshell memebr list
7 | ///
8 | public class LinkshellMemberEntryDefinition : PagedEntryDefinition
9 | {
10 | ///
11 | /// Avatar
12 | ///
13 | [JsonProperty("AVATAR")] public DefinitionsPack Avatar { get; set; }
14 |
15 | ///
16 | /// ID
17 | ///
18 | [JsonProperty("ID")] public DefinitionsPack Id { get; set; }
19 |
20 | ///
21 | /// Name
22 | ///
23 | [JsonProperty("NAME")] public DefinitionsPack Name { get; set; }
24 |
25 | ///
26 | /// Rank
27 | ///
28 | [JsonProperty("RANK")] public DefinitionsPack Rank { get; set; }
29 |
30 | ///
31 | /// Rank Icon
32 | ///
33 | [JsonProperty("RANK_ICON")] public DefinitionsPack RankIcon { get; set; }
34 |
35 | ///
36 | /// Linkshell rank
37 | ///
38 | [JsonProperty("LINKSHELL_RANK")] public DefinitionsPack LinkshellRank { get; set; }
39 |
40 | ///
41 | /// Linkshell rank Icon
42 | ///
43 | [JsonProperty("LINKSHELL_RANK_ICON")] public DefinitionsPack LinkshellRankIcon { get; set; }
44 |
45 | ///
46 | /// Server
47 | ///
48 | [JsonProperty("SERVER")] public DefinitionsPack Server { get; set; }
49 | }
--------------------------------------------------------------------------------
/NetStone/Definitions/Model/Linkshell/LinkshellSearchEntryDefinition.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 |
3 | namespace NetStone.Definitions.Model.Linkshell;
4 |
5 | ///
6 | /// Definition container for one Link-Shell search result entry
7 | ///
8 | public class LinkshellSearchEntryDefinition : PagedEntryDefinition
9 | {
10 | ///
11 | /// ID
12 | ///
13 | [JsonProperty("ID")] public DefinitionsPack Id { get; set; }
14 |
15 | ///
16 | /// Name
17 | ///
18 | [JsonProperty("NAME")] public DefinitionsPack Name { get; set; }
19 |
20 | ///
21 | /// Rank
22 | ///
23 | [JsonProperty("SERVER")] public DefinitionsPack Server { get; set; }
24 |
25 | ///
26 | /// Rank Icon
27 | ///
28 | [JsonProperty("ACTIVE_MEMBERS")] public DefinitionsPack ActiveMembers { get; set; }
29 | }
--------------------------------------------------------------------------------
/NetStone/Definitions/Model/MetaDefinition.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 |
3 | namespace NetStone.Definitions.Model;
4 |
5 | ///
6 | /// Hold information about the uri for which the definition packs are valid
7 | ///
8 | public class ApplicableUris
9 | {
10 | ///
11 | /// Uri that holds information about FC focus
12 | ///
13 | [JsonProperty("freecompany/focus.json")]
14 | public string? FreecompanyFocusJson { get; set; }
15 |
16 | ///
17 | /// Uri that holds information about FC
18 | ///
19 | [JsonProperty("freecompany/freecompany.json")]
20 | public string? FreecompanyFreecompanyJson { get; set; }
21 |
22 | ///
23 | /// Uri that holds information about FC members
24 | ///
25 | [JsonProperty("freecompany/members.json")]
26 | public string? FreecompanyMembersJson { get; set; }
27 |
28 | ///
29 | /// Uri that holds information about FC reputation
30 | ///
31 | [JsonProperty("freecompany/reputation.json")]
32 | public string? FreecompanyReputationJson { get; set; }
33 |
34 | ///
35 | /// Uri that holds information about FC recruitment
36 | ///
37 | [JsonProperty("freecompany/seeking.json")]
38 | public string? FreecompanySeekingJson { get; set; }
39 |
40 | ///
41 | /// Uri that holds information about Cross World Link Shells
42 | ///
43 | [JsonProperty("cwls/cwls.json")]
44 | public string? LinkshellCrossworldCwlsJson { get; set; }
45 |
46 | ///
47 | /// Uri that holds information about Cross World Link Shell members
48 | ///
49 | [JsonProperty("cwls/members.json")]
50 | public string? LinkshellCrossworldMembersJson { get; set; }
51 |
52 |
53 | ///
54 | /// Uri that holds information about Link Shells
55 | ///
56 | [JsonProperty("linkshell/ls.json")]
57 | public string? LinkshellLsJson { get; set; }
58 |
59 |
60 | ///
61 | /// Uri that holds information about Link Shell members
62 | ///
63 | [JsonProperty("linkshell/members.json")]
64 | public string? LinkshellMembersJson { get; set; }
65 |
66 |
67 | ///
68 | /// Uri that holds information about a character's achievements
69 | ///
70 | [JsonProperty("profile/achievements.json")]
71 | public string? ProfileAchievementsJson { get; set; }
72 |
73 | ///
74 | /// Uri that holds information about a character's attributes
75 | ///
76 | [JsonProperty("profile/attributes.json")]
77 | public string? ProfileAttributesJson { get; set; }
78 |
79 | ///
80 | /// Uri that holds information about a character
81 | ///
82 | [JsonProperty("profile/character.json")]
83 | public string? ProfileCharacterJson { get; set; }
84 |
85 | ///
86 | /// Uri that holds information about a character jobs/classes
87 | ///
88 | [JsonProperty("profile/classjob.json")]
89 | public string? ProfileClassjobJson { get; set; }
90 |
91 | ///
92 | /// Uri that holds information about a character's gear
93 | ///
94 | [JsonProperty("profile/gearset.json")]
95 | public string? ProfileGearsetJson { get; set; }
96 |
97 | ///
98 | /// Uri that holds information about a character's minions
99 | ///
100 | [JsonProperty("profile/minion.json")]
101 | public string? ProfileMinionJson { get; set; }
102 |
103 | ///
104 | /// Uri that holds information about a character's mounts
105 | ///
106 | [JsonProperty("profile/mount.json")]
107 | public string? ProfileMountJson { get; set; }
108 |
109 | ///
110 | /// Uri that holds information about a PVP team's members
111 | ///
112 | [JsonProperty("pvpteam/members.json")]
113 | public string? PvpteamMembersJson { get; set; }
114 |
115 | ///
116 | /// Uri that holds information about a PVP team
117 | ///
118 | [JsonProperty("pvpteam/pvpteam.json")]
119 | public string? PvpteamPvpteamJson { get; set; }
120 |
121 | ///
122 | /// Uri that let's you search characters
123 | ///
124 | [JsonProperty("search/character.json")]
125 | public string? SearchCharacterJson { get; set; }
126 |
127 | ///
128 | /// Uri that let's you search Cross World Link Shells
129 | ///
130 | [JsonProperty("search/cwls.json")]
131 | public string? SearchCwlsJson { get; set; }
132 |
133 | ///
134 | /// Uri that let's you search Free Companies
135 | ///
136 | [JsonProperty("search/freecompany.json")]
137 | public string? SearchFreecompanyJson { get; set; }
138 |
139 | ///
140 | /// Uri that let's you search Linkshells
141 | ///
142 | [JsonProperty("search/linkshell.json")]
143 | public string? SearchLinkshellJson { get; set; }
144 |
145 | ///
146 | /// Uri that let's you search PvP teams
147 | ///
148 | [JsonProperty("search/pvpteam.json")]
149 | public string? SearchPvpteamJson { get; set; }
150 | }
151 |
152 | ///
153 | /// Holds meta information regarding the definitions
154 | ///
155 | public class MetaDefinition : IDefinition
156 | {
157 | ///
158 | /// Version
159 | ///
160 | [JsonProperty("version")]
161 | public string Version { get; set; }
162 |
163 | ///
164 | /// User Agent used to get desktop version of Lodestone
165 | ///
166 | [JsonProperty("userAgentDesktop")]
167 | public string UserAgentDesktop { get; set; }
168 |
169 | ///
170 | /// User Agent used to get mobile version of Lodestone
171 | ///
172 | [JsonProperty("userAgentMobile")]
173 | public string UserAgentMobile { get; set; }
174 |
175 | ///
176 | /// Collection of Uris for which the definition packs are valid
177 | ///
178 | [JsonProperty("applicableUris")]
179 | public ApplicableUris ApplicableUris { get; set; }
180 | }
--------------------------------------------------------------------------------
/NetStone/Definitions/Model/PagedDefinition.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using Newtonsoft.Json.Linq;
3 |
4 | namespace NetStone.Definitions.Model;
5 |
6 | ///
7 | /// Base definition for paged results
8 | ///
9 | public class PagedDefinition : IDefinition where TEntry : PagedEntryDefinition
10 | {
11 | ///
12 | /// Root node
13 | ///
14 | [JsonProperty("ROOT")]
15 | public DefinitionsPack Root { get; set; }
16 |
17 | ///
18 | /// Definition for one entry
19 | ///
20 | [JsonProperty("ENTRY")]
21 | public TEntry Entry { get; set; }
22 |
23 | ///
24 | /// Info about pages
25 | ///
26 | [JsonProperty("PAGE_INFO")]
27 | public DefinitionsPack PageInfo { get; set; }
28 |
29 | ///
30 | /// Button for next page
31 | ///
32 | [JsonProperty("LIST_NEXT_BUTTON")]
33 | public DefinitionsPack ListNextButton { get; set; }
34 |
35 | ///
36 | /// DEfinition for node for empty results
37 | ///
38 | [JsonProperty("NO_RESULTS_FOUND")]
39 | public DefinitionsPack? NoResultsFound { get; set; }
40 | }
41 |
42 | ///
43 | /// Base definition of a paged entry
44 | ///
45 | public class PagedEntryDefinition
46 | {
47 | ///
48 | /// Root node of entry
49 | ///
50 | [JsonProperty("ROOT")]
51 | public DefinitionsPack Root { get; set; }
52 | }
--------------------------------------------------------------------------------
/NetStone/Definitions/XivApiDefinitionsContainer.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Net.Http;
3 | using System.Threading.Tasks;
4 | using NetStone.Definitions.Model;
5 | using NetStone.Definitions.Model.Character;
6 | using NetStone.Definitions.Model.CWLS;
7 | using NetStone.Definitions.Model.FreeCompany;
8 | using NetStone.Definitions.Model.Linkshell;
9 | using Newtonsoft.Json;
10 |
11 | namespace NetStone.Definitions;
12 |
13 | ///
14 | /// Holds the definitions on how to find and parse values from Lodestone HTML
15 | ///
16 | public class XivApiDefinitionsContainer : DefinitionsContainer
17 | {
18 | private const string DefinitionRepoBase = "https://raw.githubusercontent.com/xivapi/lodestone-css-selectors/main/";
19 |
20 | private readonly HttpClient client;
21 |
22 | ///
23 | /// Constructs this class without populating definitions
24 | ///
25 | public XivApiDefinitionsContainer()
26 | {
27 | this.client = new HttpClient
28 | {
29 | BaseAddress = new Uri(DefinitionRepoBase),
30 | };
31 | }
32 |
33 | ///
34 | /// Fetches current CSS selector definitions from xivapi/lodestone-css-selectors github repository.
35 | ///
36 | ///
37 | ///
38 | /// Task for this operation
39 | public override async Task Reload()
40 | {
41 | this.Meta = await GetDefinition("meta.json");
42 |
43 | this.Character = await GetDefinition("profile/character.json");
44 | this.ClassJob = await GetDefinition("profile/classjob.json");
45 | this.Gear = await GetDefinition("profile/gearset.json");
46 | this.Attributes = await GetDefinition("profile/attributes.json");
47 | this.Achievement = await GetDefinition("profile/achievements.json");
48 | this.Mount = await GetDefinition("profile/mount.json");
49 | this.Minion = await GetDefinition("profile/minion.json");
50 |
51 | this.FreeCompany = await GetDefinition("freecompany/freecompany.json");
52 | this.FreeCompanyFocus = await GetDefinition("freecompany/focus.json");
53 | this.FreeCompanyReputation =
54 | await GetDefinition("freecompany/reputation.json");
55 |
56 | this.FreeCompanyMembers = await GetDefinition>("freecompany/members.json");
57 |
58 | this.CharacterSearch = await GetDefinition>("search/character.json");
59 | this.FreeCompanySearch = await GetDefinition>("search/freecompany.json");
60 |
61 | this.CrossworldLinkshell = await GetDefinition("cwls/cwls.json");
62 | this.CrossworldLinkshellMember = await GetDefinition>("cwls/members.json");
63 | this.CrossworldLinkshellSearch = await GetDefinition>("search/cwls.json");
64 |
65 | this.Linkshell = await GetDefinition("linkshell/ls.json");
66 | this.LinkshellMember = await GetDefinition>("linkshell/members.json");
67 | this.LinkshellSearch = await GetDefinition>("search/linkshell.json");
68 | }
69 |
70 | private async Task GetDefinition(string path) where T : IDefinition
71 | {
72 | var json = await this.client.GetStringAsync(path);
73 | var result = JsonConvert.DeserializeObject(json);
74 | return result == null ? throw new FormatException($"Could not parse definitions in {path}.") : result;
75 | }
76 |
77 | ///
78 | public override void Dispose()
79 | {
80 | this.client.Dispose();
81 | }
82 | }
--------------------------------------------------------------------------------
/NetStone/GameData/GameDataInfo.cs:
--------------------------------------------------------------------------------
1 | namespace NetStone.GameData;
2 |
3 | ///
4 | /// Generic container for game data
5 | ///
6 | public struct GameDataInfo
7 | {
8 | ///
9 | /// Key /ID of data
10 | ///
11 | public uint Key { get; set; }
12 |
13 | ///
14 | /// Name
15 | ///
16 | public string Name { get; set; }
17 | }
--------------------------------------------------------------------------------
/NetStone/GameData/GenderedGameData.cs:
--------------------------------------------------------------------------------
1 | namespace NetStone.GameData;
2 |
3 | ///
4 | /// Game data with different names depending on gender
5 | ///
6 | public struct GenderedGameData
7 | {
8 | ///
9 | /// Basic game data
10 | ///
11 | public GameDataInfo Info { get; set; }
12 |
13 | ///
14 | /// Masculine name
15 | ///
16 | public LanguageStrings NameMasc { get; set; }
17 |
18 | ///
19 | /// Feminine name
20 | ///
21 | public LanguageStrings NameFem { get; set; }
22 | }
--------------------------------------------------------------------------------
/NetStone/GameData/IGameDataProvider.cs:
--------------------------------------------------------------------------------
1 | namespace NetStone.GameData;
2 |
3 | ///
4 | /// Needed interface for a provider of game data
5 | ///
6 | public interface IGameDataProvider
7 | {
8 | ///
9 | /// Get item data by name.
10 | ///
11 | /// Name of the item
12 | /// Game data
13 | public NamedGameData? GetItem(string name);
14 | }
--------------------------------------------------------------------------------
/NetStone/GameData/LanguageStrings.cs:
--------------------------------------------------------------------------------
1 | namespace NetStone.GameData;
2 |
3 | ///
4 | /// Container for localized strings
5 | ///
6 | public struct LanguageStrings
7 | {
8 | ///
9 | /// English
10 | ///
11 | public string En { get; set; }
12 |
13 | ///
14 | /// German
15 | ///
16 | public string De { get; set; }
17 |
18 | ///
19 | /// Japanese
20 | ///
21 | public string Ja { get; set; }
22 |
23 | ///
24 | /// French
25 | ///
26 | public string Fr { get; set; }
27 | }
--------------------------------------------------------------------------------
/NetStone/GameData/NamedGameData.cs:
--------------------------------------------------------------------------------
1 | namespace NetStone.GameData;
2 |
3 | ///
4 | /// Game data with localized name
5 | ///
6 | public struct NamedGameData
7 | {
8 | ///
9 | /// Base data
10 | ///
11 | public GameDataInfo Info { get; set; }
12 |
13 | ///
14 | /// Localized name
15 | ///
16 | public LanguageStrings Name { get; set; }
17 | }
--------------------------------------------------------------------------------
/NetStone/GameData/TitleGameData.cs:
--------------------------------------------------------------------------------
1 | namespace NetStone.GameData;
2 |
3 | ///
4 | /// Game data for titles
5 | ///
6 | public struct TitleGameData
7 | {
8 | ///
9 | /// Localized title
10 | ///
11 | public NamedGameData Names { get; set; }
12 |
13 | ///
14 | /// Indicates if before name
15 | ///
16 | public bool Prefix { get; set; }
17 | }
--------------------------------------------------------------------------------
/NetStone/Model/IOptionalParseable.cs:
--------------------------------------------------------------------------------
1 | namespace NetStone.Model;
2 |
3 | ///
4 | /// Interface indicating an optional parsed object that may or may not exist.
5 | ///
6 | /// LodestoneParseable to be marked optional
7 | public interface IOptionalParseable where T : LodestoneParseable
8 | {
9 | ///
10 | /// Value indicating if the object should be populated.
11 | ///
12 | bool Exists { get; }
13 | }
14 |
15 | ///
16 | ///
17 | ///
18 | public static class OptionalExtensions
19 | {
20 | ///
21 | /// Method returning the object itself if exists.
22 | ///
23 | /// this if Exists == True
24 | public static T? GetOptional(this IOptionalParseable opt) where T : LodestoneParseable
25 | {
26 | if (opt.Exists)
27 | return opt as T;
28 |
29 | return null;
30 | }
31 | }
--------------------------------------------------------------------------------
/NetStone/Model/IPaginatedResult.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Threading.Tasks;
4 | using HtmlAgilityPack;
5 | using NetStone.Definitions.Model;
6 | using NetStone.Search;
7 |
8 | namespace NetStone.Model;
9 |
10 | ///
11 | /// Models data that is presented over multiple pages
12 | ///
13 | /// Type of data presented
14 | public interface IPaginatedResult where T : LodestoneParseable
15 | {
16 | ///
17 | /// Currently handled page
18 | ///
19 | int CurrentPage { get; }
20 |
21 | ///
22 | /// Total number of pages
23 | ///
24 | int NumPages { get; }
25 |
26 | ///
27 | /// Gets the next page of results
28 | ///
29 | /// Task of retrieving next page
30 | Task GetNextPage();
31 | }
32 |
33 | ///
34 | /// Container class holding paginated information
35 | ///
36 | public abstract class PaginatedIdResult
37 | : PaginatedResult where TPage : LodestoneParseable
38 | where TEntry : LodestoneParseable
39 | where TEntryDef : PagedEntryDefinition
40 | {
41 | ///
42 | protected PaginatedIdResult(HtmlNode rootNode, PagedDefinition pageDefinition,
43 | Func> nextPageFunc, string id)
44 | : base(rootNode, pageDefinition, nextPageFunc, id)
45 | {
46 | }
47 | }
48 | ///
49 | /// Container class holding paginated information
50 | ///
51 | public abstract class PaginatedSearchResult
52 | : PaginatedResult where TPage : LodestoneParseable
53 | where TEntry : LodestoneParseable
54 | where TEntryDef : PagedEntryDefinition
55 | where TQuery : ISearchQuery
56 | {
57 | ///
58 | protected PaginatedSearchResult(HtmlNode rootNode, PagedDefinition pageDefinition,
59 | Func> nextPageFunc,
60 | TQuery query)
61 | : base(rootNode, pageDefinition, nextPageFunc, query)
62 | {
63 | }
64 | }
65 |
66 |
67 | ///
68 | /// Container class holding paginated information
69 | ///
70 | public abstract class PaginatedResult : LodestoneParseable, IPaginatedResult where TPage : LodestoneParseable where TEntry : LodestoneParseable where TEntryDef : PagedEntryDefinition
71 | {
72 | ///
73 | /// Definition for the paginated type
74 | ///
75 | protected readonly PagedDefinition PageDefinition;
76 |
77 | private readonly TRequest request;
78 |
79 | private readonly Func> nextPageFunc;
80 |
81 | ///
82 | ///
83 | ///
84 | /// The root document node of the page
85 | /// CSS definitions for the paginated type
86 | /// Function to retrieve a page of this type
87 | /// The input used to request further pages.
88 | protected PaginatedResult(HtmlNode rootNode, PagedDefinition pageDefinition,Func> nextPageFunc, TRequest request) : base(rootNode)
89 | {
90 | this.PageDefinition = pageDefinition;
91 | this.request = request;
92 | this.nextPageFunc = nextPageFunc;
93 | }
94 |
95 | ///
96 | /// If there is any data
97 | ///
98 | public bool HasResults => this.PageDefinition.NoResultsFound is null || !HasNode(this.PageDefinition.NoResultsFound);
99 |
100 | private TEntry[]? parsedResults;
101 |
102 | ///
103 | /// List of members
104 | ///
105 | protected IEnumerable Results
106 | {
107 | get
108 | {
109 | if (!this.HasResults) return Array.Empty();
110 | this.parsedResults ??= ParseResults();
111 | return this.parsedResults;
112 | }
113 | }
114 |
115 | ///
116 | /// Creates the array of all entries on this page>
117 | ///
118 | protected abstract TEntry[] ParseResults();
119 |
120 | private int? currentPageVal;
121 |
122 | ///
123 | public int CurrentPage
124 | {
125 | get
126 | {
127 | if (!this.HasResults)
128 | return 0;
129 | if (!this.currentPageVal.HasValue)
130 | ParsePagesCount();
131 |
132 | return this.currentPageVal!.Value;
133 | }
134 | }
135 |
136 | private int? numPagesVal;
137 |
138 | ///
139 | public int NumPages
140 | {
141 | get
142 | {
143 | if (!this.HasResults)
144 | return 0;
145 | if (!this.numPagesVal.HasValue)
146 | ParsePagesCount();
147 |
148 | return this.numPagesVal!.Value;
149 | }
150 | }
151 | private void ParsePagesCount()
152 | {
153 | var results = ParseRegex(this.PageDefinition.PageInfo);
154 |
155 | this.currentPageVal = int.Parse(results["CurrentPage"].Value);
156 | this.numPagesVal = int.Parse(results["NumPages"].Value);
157 | }
158 |
159 | ///
160 | public async Task GetNextPage()
161 | {
162 | if (!this.HasResults)
163 | return null;
164 |
165 | if (this.CurrentPage == this.NumPages)
166 | return null;
167 |
168 | return await this.nextPageFunc(this.request, this.CurrentPage + 1);
169 | }
170 | }
--------------------------------------------------------------------------------
/NetStone/Model/Parseables/CWLS/LodestoneCrossworldLinkshell.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using HtmlAgilityPack;
3 | using NetStone.Definitions;
4 | using NetStone.Definitions.Model.CWLS;
5 | using NetStone.Model.Parseables.CWLS.Members;
6 |
7 | namespace NetStone.Model.Parseables.CWLS;
8 |
9 | ///
10 | /// Container class holding information about a cross world linkshell and it's members.
11 | ///
12 | public class LodestoneCrossworldLinkshell : PaginatedIdResult
13 | {
14 |
15 | private readonly CrossworldLinkshellDefinition definition;
16 |
17 | ///
18 | /// Container class for a parseable corss world linkshell page.
19 | ///
20 | /// The to be used to fetch further information.
21 | /// The root document node of the page.
22 | /// The holding definitions to be used to access data.
23 | /// The ID of the cross world linkshell.
24 | public LodestoneCrossworldLinkshell(LodestoneClient client, HtmlNode rootNode, DefinitionsContainer container, string id)
25 | : base(rootNode,container.CrossworldLinkshellMember,client.GetCrossworldLinkshell,id)
26 | {
27 | this.definition = container.CrossworldLinkshell;
28 | }
29 |
30 | ///
31 | /// Name
32 | ///
33 | public string Name => ParseDirectInnerText(this.definition.Name).Trim();
34 |
35 | ///
36 | /// Datacenter
37 | ///
38 | public string DataCenter => Parse(this.definition.DataCenter);
39 |
40 | ///
41 | /// Members
42 | ///
43 | public IEnumerable Members => this.Results;
44 |
45 | ///
46 | protected override CrossworldLinkshellMemberEntry[] ParseResults()
47 | {
48 | var nodes = QueryContainer(this.PageDefinition);
49 |
50 | var parsedResults = new CrossworldLinkshellMemberEntry[nodes.Length];
51 | for (var i = 0; i < parsedResults.Length; i++)
52 | {
53 | parsedResults[i] = new CrossworldLinkshellMemberEntry(nodes[i], this.PageDefinition.Entry);
54 | }
55 | return parsedResults;
56 | }
57 | }
--------------------------------------------------------------------------------
/NetStone/Model/Parseables/CWLS/Members/CrossworldLinkshellMemberEntry.cs:
--------------------------------------------------------------------------------
1 | using HtmlAgilityPack;
2 | using NetStone.Definitions.Model.CWLS;
3 |
4 | namespace NetStone.Model.Parseables.CWLS.Members;
5 |
6 | ///
7 | /// Container class holding information about a cross-world linkshell member.
8 | ///
9 | public class CrossworldLinkshellMemberEntry : LodestoneParseable
10 | {
11 | private readonly CrossworldLinkshellMemberEntryDefinition definition;
12 | ///
13 | /// Create instance of member entry for a given node
14 | ///
15 | /// Root html node of this entry
16 | /// Css and regex definition
17 | public CrossworldLinkshellMemberEntry(HtmlNode rootNode, CrossworldLinkshellMemberEntryDefinition definition) : base(rootNode)
18 | {
19 | this.definition = definition;
20 | }
21 |
22 | ///
23 | /// Avatar
24 | ///
25 | public string Avatar => Parse(this.definition.Avatar);
26 |
27 | ///
28 | /// ID
29 | ///
30 | public string? Id => ParseHrefId(this.definition.Id);
31 |
32 | ///
33 | /// Name
34 | ///
35 | public string Name => Parse(this.definition.Name);
36 |
37 | ///
38 | /// Rank
39 | ///
40 | public string Rank => Parse(this.definition.Rank);
41 |
42 | ///
43 | /// Rank Icon
44 | ///
45 | public string RankIcon => Parse(this.definition.RankIcon);
46 |
47 | ///
48 | /// Linkshell rank
49 | ///
50 | public string LinkshellRank => Parse(this.definition.LinkshellRank);
51 |
52 | ///
53 | /// Linkshell rank Icon
54 | ///
55 | public string LinkshellRankIcon => Parse(this.definition.LinkshellRankIcon);
56 |
57 | ///
58 | /// Server
59 | ///
60 | public string Server => Parse(this.definition.Server);
61 | }
--------------------------------------------------------------------------------
/NetStone/Model/Parseables/Character/Achievement/CharacterAchievementEntry.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq;
3 | using HtmlAgilityPack;
4 | using NetStone.Definitions.Model.Character;
5 |
6 | namespace NetStone.Model.Parseables.Character.Achievement;
7 |
8 | ///
9 | /// Models data for one Achievement this character earned
10 | ///
11 | public class CharacterAchievementEntry : LodestoneParseable
12 | {
13 | private readonly CharacterAchievementEntryDefinition definition;
14 |
15 | ///
16 | /// Create instance of achievement entry fpr given node
17 | ///
18 | /// Root html node of this entry
19 | /// Css and regex definition
20 | public CharacterAchievementEntry(HtmlNode rootNode, CharacterAchievementEntryDefinition definition) : base(rootNode)
21 | {
22 | this.definition = definition;
23 | }
24 |
25 | ///
26 | /// The Name of this achievement
27 | ///
28 | #if NETSTANDARD2_1
29 | public string Name => ParseRegex(this.definition.Name).First(r => r.Name.Equals("Name")).Value;
30 | #else
31 | public string Name => ParseRegex(this.definition.Name).Values.First(r => r.Name.Equals("Name")).Value;
32 | #endif
33 | ///
34 | /// ID of this achievement
35 | ///
36 | public ulong? Id => ParseHrefIdULong(this.definition.Id);
37 |
38 | ///
39 | /// Link to the Eorzean Database
40 | ///
41 | public Uri? DatabaseLink => ParseHref(this.definition.Id);
42 |
43 | ///
44 | /// Time when this character earned this achievement
45 | ///
46 | public DateTime TimeAchieved => ParseTime(this.definition.Time);
47 |
48 | ///
49 | public override string ToString() => this.Name;
50 | }
--------------------------------------------------------------------------------
/NetStone/Model/Parseables/Character/Achievement/CharacterAchievementPage.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using HtmlAgilityPack;
3 | using NetStone.Definitions.Model.Character;
4 |
5 | namespace NetStone.Model.Parseables.Character.Achievement;
6 |
7 | ///
8 | /// Holds information about a characters unlocked achievements
9 | ///
10 | public class CharacterAchievementPage : PaginatedIdResult
11 | {
12 | private readonly CharacterAchievementDefinition definition;
13 |
14 | ///
15 | /// Creates a new instance retrieving information about a characters unlocked achievements
16 | ///
17 | /// Lodestone client instance
18 | /// Root node of the achievement page
19 | /// Parse definition pack
20 | /// ID of the character
21 | public CharacterAchievementPage(LodestoneClient client, HtmlNode rootNode,
22 | CharacterAchievementDefinition definition,string charId)
23 | : base(rootNode, definition, client.GetCharacterAchievement, charId)
24 | {
25 | this.definition = definition;
26 | }
27 |
28 | ///
29 | /// Total number of achievements
30 | ///
31 | public int TotalAchievements
32 | {
33 | get
34 | {
35 | var res = ParseRegex(this.definition.TotalAchievements);
36 | return int.Parse(res["TotalAchievements"].Value);
37 | }
38 | }
39 |
40 | ///
41 | /// Number of achievement points for this character
42 | ///
43 | public int AchievementPoints => int.Parse(Parse(this.definition.AchievementPoints));
44 |
45 | ///
46 | /// Unlocked achievements for character
47 | ///
48 | public IEnumerable Achievements => this.Results;
49 |
50 | ///
51 | protected override CharacterAchievementEntry[] ParseResults()
52 | {
53 | var nodes = QueryContainer(this.definition);
54 |
55 | var parsedResults = new CharacterAchievementEntry[nodes.Length];
56 | for (var i = 0; i < parsedResults.Length; i++)
57 | {
58 | parsedResults[i] = new CharacterAchievementEntry(nodes[i], this.definition.Entry);
59 | }
60 | return parsedResults;
61 | }
62 | }
--------------------------------------------------------------------------------
/NetStone/Model/Parseables/Character/CharacterAttributes.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using HtmlAgilityPack;
3 | using NetStone.Definitions.Model.Character;
4 |
5 | namespace NetStone.Model.Parseables.Character;
6 |
7 | ///
8 | /// Provides information about a characters attributes
9 | ///
10 | public class CharacterAttributes : LodestoneParseable
11 | {
12 | private readonly CharacterAttributesDefinition definition;
13 |
14 | ///
15 | /// Creates an instance that provides Attributes for given node
16 | ///
17 | /// Root HTML node of the character profile page on Lodestone
18 | /// Definitions on how to parse attributes from the HTML
19 | public CharacterAttributes(HtmlNode rootNode, CharacterAttributesDefinition definition) : base(rootNode)
20 | {
21 | this.definition = definition;
22 | }
23 |
24 | ///
25 | /// This characters' Strength value.
26 | ///
27 | public int Strength => int.Parse(Parse(this.definition.Strength));
28 |
29 | ///
30 | /// This characters' Dexterity value.
31 | ///
32 | public int Dexterity => int.Parse(Parse(this.definition.Dexterity));
33 |
34 | ///
35 | /// This characters' Vitality value.
36 | ///
37 | public int Vitality => int.Parse(Parse(this.definition.Vitality));
38 |
39 | ///
40 | /// This characters' Intelligence value.
41 | ///
42 | public int Intelligence => int.Parse(Parse(this.definition.Intelligence));
43 |
44 | ///
45 | /// This characters' Mind value.
46 | ///
47 | public int Mind => int.Parse(Parse(this.definition.Mind));
48 |
49 | ///
50 | /// This characters' Critical Hit Rate value.
51 | ///
52 | public int CriticalHitRate => int.Parse(Parse(this.definition.CriticalHitRate));
53 |
54 | ///
55 | /// This characters' Determination value.
56 | ///
57 | public int Determination => int.Parse(Parse(this.definition.Determination));
58 |
59 | ///
60 | /// This characters' Direct Hit Rate value.
61 | ///
62 | public int DirectHitRate => int.Parse(Parse(this.definition.DirectHitRate));
63 |
64 | ///
65 | /// This characters' Defense value.
66 | ///
67 | public int Defense => int.Parse(Parse(this.definition.Defense));
68 |
69 | ///
70 | /// This characters' Magic Defense value.
71 | ///
72 | public int MagicDefense => int.Parse(Parse(this.definition.MagicDefense));
73 |
74 | ///
75 | /// This characters' Attack Power value.
76 | ///
77 | public int AttackPower => int.Parse(Parse(this.definition.AttackPower));
78 |
79 | ///
80 | /// This characters' Skill Speed value.
81 | ///
82 | public int SkillSpeed => int.Parse(Parse(this.definition.SkillSpeed));
83 |
84 | ///
85 | /// This characters' Attack Magic Potency value.
86 | ///
87 | /// This value is only set for disciples of war/magic.
88 | public int? AttackMagicPotency => IsDoWOrDoM() ? this.AttackMagicPotencyInternal : null;
89 |
90 | ///
91 | /// This characters' Healing Magic Potency value.
92 | ///
93 | /// This value is only set for disciples of war/magic.
94 | public int? HealingMagicPotency => IsDoWOrDoM() ? this.HealingMagicPotencyInternal : null;
95 |
96 | ///
97 | /// This characters' Spell Speed value.
98 | ///
99 | /// This value is only set for disciples of war/magic.
100 | public int? SpellSpeed => int.TryParse(Parse(this.definition.SpellSpeed), out var result) ? result : null;
101 |
102 | ///
103 | /// This characters' Tenacity value.
104 | ///
105 | public int? Tenacity => int.TryParse(Parse(this.definition.Tenacity), out var result) ? result : null;
106 |
107 | ///
108 | /// This characters' Piety value.
109 | ///
110 | public int? Piety => int.TryParse(Parse(this.definition.Piety), out var result) ? result : null;
111 |
112 | ///
113 | /// This characters' Craftmanship value.
114 | ///
115 | /// This value is only set for disciples of the hand.
116 | public int? Craftsmanship => IsDoH() ? this.AttackMagicPotencyInternal : null;
117 |
118 | ///
119 | /// This characters' Control value.
120 | ///
121 | /// This value is only set for disciples of the hand.
122 | public int? Control => IsDoH() ? this.HealingMagicPotencyInternal : null;
123 |
124 | ///
125 | /// This characters' Gathering value.
126 | ///
127 | /// This value is only set for disciples of the land.
128 | public int? Gathering => IsDoL() ? this.AttackMagicPotencyInternal : null;
129 |
130 | ///
131 | /// This characters' Perception value.
132 | ///
133 | /// This value is only set for disciples of the land.
134 | public int? Perception => IsDoL() ? this.HealingMagicPotencyInternal : null;
135 |
136 | ///
137 | /// This characters' HP value.
138 | ///
139 | public int Hp => int.Parse(Parse(this.definition.Hp));
140 |
141 | ///
142 | /// This characters' MP, GP or CP value. Check the Property to find out which.
143 | ///
144 | public int MpGpCp => int.Parse(Parse(this.definition.MpGpCp));
145 |
146 | ///
147 | /// Value indicating which of MP, GP, or CP is indicated by .
148 | ///
149 | public string MpGpCpParameterName => Parse(this.definition.MpGpCpParameterName);
150 |
151 | internal bool IsDoL() => this.MpGpCpParameterName.Equals("GP", StringComparison.InvariantCultureIgnoreCase);
152 | internal bool IsDoWOrDoM() => this.MpGpCpParameterName.Equals("MP", StringComparison.InvariantCultureIgnoreCase);
153 | internal bool IsDoH() => this.MpGpCpParameterName.Equals("CP", StringComparison.InvariantCultureIgnoreCase);
154 |
155 | internal int AttackMagicPotencyInternal => int.TryParse(Parse(this.definition.AttackMagicPotency), out var val) ? val : 0;
156 |
157 | internal int HealingMagicPotencyInternal => int.TryParse(Parse(this.definition.HealingMagicPotency), out var val) ? val : 0;
158 | }
--------------------------------------------------------------------------------
/NetStone/Model/Parseables/Character/ClassJob/ClassJobBozja.cs:
--------------------------------------------------------------------------------
1 | using System.Linq;
2 | using System.Text.RegularExpressions;
3 | using HtmlAgilityPack;
4 | using NetStone.Definitions.Model.Character;
5 |
6 | namespace NetStone.Model.Parseables.Character.ClassJob;
7 |
8 | ///
9 | /// Entry for Bozja Field Operation of a character
10 | ///
11 | public class ClassJobBozja : LodestoneParseable, IOptionalParseable
12 | {
13 | private readonly ClassJobBozjaDefinition definition;
14 |
15 | ///
16 | /// Constructs a new class entry
17 | ///
18 | /// Root node of this entry
19 | /// Parser definition
20 | public ClassJobBozja(HtmlNode rootNode, ClassJobBozjaDefinition definition) : base(rootNode)
21 | {
22 | this.definition = definition;
23 | }
24 |
25 | ///
26 | /// The name of this class and job combo.
27 | ///
28 | public string Name => Parse(this.definition.NAME);
29 |
30 | ///
31 | /// The level this class or job is at.
32 | ///
33 | public int Level => int.TryParse(Parse(this.definition.LEVEL), out var levelOut) ? levelOut : 0 ;
34 |
35 | private string MettleString => ParseInnerText(this.definition.METTLE);
36 |
37 | private int? mettleCurrentVal;
38 |
39 | ///
40 | /// The amount of current achieved EXP on this level.
41 | ///
42 | public int MettleCurrent
43 | {
44 | get
45 | {
46 | if (!this.mettleCurrentVal.HasValue)
47 | ParseMettle();
48 |
49 | return this.mettleCurrentVal!.Value;
50 | }
51 | }
52 |
53 | private int? mettleMaxVal;
54 |
55 | ///
56 | /// The amount of EXP to be reached to gain the next level.
57 | ///
58 | public int MettleMax
59 | {
60 | get
61 | {
62 | if (!this.mettleCurrentVal.HasValue)
63 | ParseMettle();
64 |
65 | return this.mettleMaxVal!.Value;
66 | }
67 | }
68 |
69 | ///
70 | /// The outstanding amount of EXP to go to the next level.
71 | ///
72 | public int MettleToGo => this.MettleMax - this.MettleCurrent;
73 |
74 | private void ParseMettle()
75 | {
76 | if (!this.Exists)
77 | {
78 | this.mettleCurrentVal = 0;
79 | this.mettleMaxVal = 0;
80 |
81 | return;
82 | }
83 |
84 | var mettleVals = this.MettleString.Split(" / ").Select(x => x.Replace(",", string.Empty)).ToArray();
85 |
86 | this.mettleCurrentVal = int.TryParse(Regex.Match(mettleVals[0], @"\d+").Value, out var mettleCur) ? mettleCur : 0;
87 | this.mettleMaxVal = int.TryParse(Regex.Match(mettleVals[1], @"\d+").Value, out var mettleMax) ? mettleMax : 0;
88 | }
89 |
90 | ///
91 | /// Value indicating if this class is unlocked.
92 | ///
93 | public bool Exists => this.Level != 0;
94 |
95 | ///
96 | /// The string representation of this object.
97 | ///
98 | /// Name (Level)
99 | public override string ToString() => $"{this.Name} ({this.Level})";
100 | }
--------------------------------------------------------------------------------
/NetStone/Model/Parseables/Character/ClassJob/ClassJobEntry.cs:
--------------------------------------------------------------------------------
1 | using System.Linq;
2 | using HtmlAgilityPack;
3 | using NetStone.Definitions.Model.Character;
4 |
5 | namespace NetStone.Model.Parseables.Character.ClassJob;
6 |
7 | ///
8 | /// Entry for one class/job of a character
9 | ///
10 | public class ClassJobEntry : LodestoneParseable, IOptionalParseable
11 | {
12 | private readonly ClassJobEntryDefinition definition;
13 |
14 | ///
15 | /// Constructs a new class entry
16 | ///
17 | /// Root node of this entry
18 | /// Parser definition
19 | public ClassJobEntry(HtmlNode rootNode, ClassJobEntryDefinition definition) : base(rootNode)
20 | {
21 | this.definition = definition;
22 | }
23 |
24 | ///
25 | /// The name of this class and job combo.
26 | ///
27 | public string Name => ParseTooltip(this.definition.UnlockState);
28 |
29 | ///
30 | /// Value indicating whether this class has its job unlocked.
31 | ///
32 | public bool IsJobUnlocked => this.Name.Contains("/");
33 |
34 | ///
35 | /// The level this class or job is at.
36 | ///
37 | public int Level
38 | {
39 | get
40 | {
41 | var level = Parse(this.definition.Level);
42 | return level == "-" ? 0 : int.Parse(level);
43 | }
44 | }
45 |
46 | private string ExpString => ParseInnerText(this.definition.Exp);
47 |
48 | private long? expCurrentVal;
49 |
50 | ///
51 | /// The amount of current achieved EXP on this level.
52 | ///
53 | public long ExpCurrent
54 | {
55 | get
56 | {
57 | if (!this.expCurrentVal.HasValue)
58 | ParseExp();
59 |
60 | return this.expCurrentVal!.Value;
61 | }
62 | }
63 |
64 | private long? expMaxVal;
65 |
66 | ///
67 | /// The amount of EXP to be reached to gain the next level.
68 | ///
69 | public long ExpMax
70 | {
71 | get
72 | {
73 | if (!this.expCurrentVal.HasValue)
74 | ParseExp();
75 |
76 | return this.expMaxVal!.Value;
77 | }
78 | }
79 |
80 | ///
81 | /// The outstanding amount of EXP to go to the next level.
82 | ///
83 | public long ExpToGo => this.ExpMax - this.ExpCurrent;
84 |
85 | private void ParseExp()
86 | {
87 | if (!this.Exists)
88 | {
89 | this.expCurrentVal = 0;
90 | this.expMaxVal = 0;
91 |
92 | return;
93 | }
94 |
95 | var expVals = this.ExpString.Split(" / ").Select(x => x.Replace(",", string.Empty)).ToArray();
96 |
97 | if (expVals[0] == "--")
98 | {
99 | this.expCurrentVal = 0;
100 | this.expMaxVal = 0;
101 |
102 | return;
103 | }
104 |
105 | this.expCurrentVal = long.Parse(expVals[0]);
106 | this.expMaxVal = long.Parse(expVals[1]);
107 | }
108 |
109 | ///
110 | /// Value indicating whether this job, if DoH or DoL, is specialized.
111 | ///
112 | public bool IsSpecialized => ParseAttribute(this.definition.UnlockState, "class")?.Contains("--meister") ?? false;
113 |
114 | ///
115 | /// Value indicating if this class is unlocked.
116 | ///
117 | public bool Exists => this.Level != 0;
118 |
119 | ///
120 | /// Value indicating if this class is unlocked.
121 | ///
122 | public bool IsUnlocked => this.Exists;
123 |
124 | ///
125 | /// The string representation of this object.
126 | ///
127 | /// Name (Level)
128 | public override string ToString() => $"{this.Name} ({this.Level})";
129 | }
--------------------------------------------------------------------------------
/NetStone/Model/Parseables/Character/ClassJob/ClassJobEureka.cs:
--------------------------------------------------------------------------------
1 | using System.Linq;
2 | using HtmlAgilityPack;
3 | using NetStone.Definitions.Model.Character;
4 |
5 | namespace NetStone.Model.Parseables.Character.ClassJob;
6 |
7 | ///
8 | /// Entry for Eureka Field Operation of a character
9 | ///
10 | public class ClassJobEureka : LodestoneParseable, IOptionalParseable
11 | {
12 | private readonly ClassJobEurekaDefinition definition;
13 |
14 | ///
15 | /// Constructs a new class entry
16 | ///
17 | /// Root node of this entry
18 | /// Parser definition
19 | public ClassJobEureka(HtmlNode rootNode, ClassJobEurekaDefinition definition) : base(rootNode)
20 | {
21 | this.definition = definition;
22 | }
23 |
24 | ///
25 | /// The name of this class and job combo.
26 | ///
27 | public string Name => Parse(this.definition.Name);
28 |
29 | ///
30 | /// Value indicating whether this class has its job unlocked.
31 | ///
32 | public bool IsJobUnlocked => this.Name.Contains("/");
33 |
34 | ///
35 | /// The level this class or job is at.
36 | ///
37 | public int Level => int.TryParse(Parse(this.definition.Level), out var level)? level : 0;
38 |
39 | private string ExpString => ParseInnerText(this.definition.Exp);
40 |
41 | private int? expCurrentVal;
42 |
43 | ///
44 | /// The amount of current achieved EXP on this level.
45 | ///
46 | public int ExpCurrent
47 | {
48 | get
49 | {
50 | if (!this.expCurrentVal.HasValue)
51 | ParseExp();
52 |
53 | return this.expCurrentVal!.Value;
54 | }
55 | }
56 |
57 | private int? expMaxVal;
58 |
59 | ///
60 | /// The amount of EXP to be reached to gain the next level.
61 | ///
62 | public int ExpMax
63 | {
64 | get
65 | {
66 | if (!this.expCurrentVal.HasValue)
67 | ParseExp();
68 |
69 | return this.expMaxVal!.Value;
70 | }
71 | }
72 |
73 | ///
74 | /// The outstanding amount of EXP to go to the next level.
75 | ///
76 | public int ExpToGo => this.ExpMax - this.ExpCurrent;
77 |
78 | private void ParseExp()
79 | {
80 | if (!this.Exists)
81 | {
82 | this.expCurrentVal = 0;
83 | this.expMaxVal = 0;
84 |
85 | return;
86 | }
87 |
88 | var expVals = this.ExpString.Split(" / ").Select(x => x.Replace(",", string.Empty)).ToArray();
89 |
90 | this.expCurrentVal = int.TryParse(expVals[0], out var expCur) ? expCur : 0;
91 | this.expMaxVal = int.TryParse(expVals[1], out var expMax) ? expMax : 0;
92 | }
93 |
94 | ///
95 | /// Value indicating if this class is unlocked.
96 | ///
97 | public bool Exists => this.Level != 0;
98 |
99 | ///
100 | /// Value indicating if this class is unlocked.
101 | ///
102 | public bool IsUnlocked => this.Exists;
103 |
104 | ///
105 | /// The string representation of this object.
106 | ///
107 | /// Name (Level)
108 | public override string ToString() => $"{this.Name} ({this.Level})";
109 | }
--------------------------------------------------------------------------------
/NetStone/Model/Parseables/Character/Collectable/CharacterCollectable.cs:
--------------------------------------------------------------------------------
1 | using HtmlAgilityPack;
2 | using NetStone.Definitions.Model.Character;
3 |
4 | namespace NetStone.Model.Parseables.Character.Collectable;
5 |
6 | ///
7 | /// Models a collection of collectables for characters
8 | ///
9 | public class CharacterCollectable : LodestoneParseable
10 | {
11 | private readonly CharacterCollectableDefinition definition;
12 |
13 | ///
14 | /// Constructs a collectable collection
15 | ///
16 | /// Root node of list
17 | /// Parser definitions
18 | public CharacterCollectable(HtmlNode rootNode, CharacterCollectableDefinition definition) : base(rootNode)
19 | {
20 | this.definition = definition;
21 | }
22 |
23 | private CharacterCollectableEntry[]? parsedResults;
24 |
25 | ///
26 | /// All collectables collected by the character.
27 | ///
28 | public CharacterCollectableEntry[] Collectables
29 | {
30 | get
31 | {
32 | if (this.parsedResults == null)
33 | ParseCollectables();
34 |
35 | return this.parsedResults!;
36 | }
37 | }
38 |
39 | private void ParseCollectables()
40 | {
41 | var nodes = QueryChildNodes(this.definition.GetDefinitions().Root);
42 |
43 | this.parsedResults = new CharacterCollectableEntry[nodes.Length];
44 | for (var i = 0; i < this.parsedResults.Length; i++)
45 | {
46 | this.parsedResults[i] = new CharacterCollectableEntry(nodes[i], this.definition);
47 | }
48 | }
49 | }
--------------------------------------------------------------------------------
/NetStone/Model/Parseables/Character/Collectable/CharacterCollectableEntry.cs:
--------------------------------------------------------------------------------
1 | using HtmlAgilityPack;
2 | using NetStone.Definitions.Model.Character;
3 |
4 | namespace NetStone.Model.Parseables.Character.Collectable;
5 |
6 | ///
7 | /// Entry for collectable collection
8 | ///
9 | public class CharacterCollectableEntry : LodestoneParseable
10 | {
11 | private readonly CharacterCollectableDefinition definition;
12 |
13 | ///
14 | /// Constructs one collectable entry
15 | ///
16 | /// Root node for entry
17 | /// Parse definition
18 | public CharacterCollectableEntry(HtmlNode rootNode, CharacterCollectableDefinition definition) : base(rootNode)
19 | {
20 | this.definition = definition;
21 | }
22 |
23 | ///
24 | /// The name of this collectable.
25 | ///
26 | public string Name => Parse(this.definition.GetDefinitions().Name);
27 |
28 | ///
29 | /// The string representation of this collectable.
30 | ///
31 | ///
32 | public override string ToString() => this.Name;
33 | }
--------------------------------------------------------------------------------
/NetStone/Model/Parseables/Character/FreeCompanySocialGroup.cs:
--------------------------------------------------------------------------------
1 | using System.Threading.Tasks;
2 | using HtmlAgilityPack;
3 | using NetStone.Definitions.Model.Character;
4 | using NetStone.Model.Parseables.FreeCompany;
5 |
6 | namespace NetStone.Model.Parseables.Character;
7 |
8 | ///
9 | /// Models a Free Company entry on the character profile
10 | ///
11 | public class FreeCompanySocialGroup : SocialGroup
12 | {
13 | private readonly LodestoneClient client;
14 |
15 | ///
16 | /// Constructs FC entry for profile page
17 | ///
18 | ///
19 | ///
20 | ///
21 | public FreeCompanySocialGroup(LodestoneClient client, HtmlNode rootNode,
22 | ICharacterSocialGroupDefinition socialGroupDefinition) : base(rootNode, socialGroupDefinition)
23 | {
24 | this.client = client;
25 | }
26 |
27 | ///
28 | /// Fetch the full details of this FC.
29 | ///
30 | /// object containing all details of the free company.
31 | public async Task GetDetails() =>
32 | this.Id is null ? null : await this.client.GetFreeCompany(this.Id);
33 | }
--------------------------------------------------------------------------------
/NetStone/Model/Parseables/Character/Gear/CharacterGear.cs:
--------------------------------------------------------------------------------
1 | using HtmlAgilityPack;
2 | using NetStone.Definitions.Model.Character;
3 |
4 | namespace NetStone.Model.Parseables.Character.Gear;
5 |
6 | ///
7 | /// Container class holding information about a character's equipped gear.
8 | ///
9 | public class CharacterGear : LodestoneParseable
10 | {
11 | private readonly LodestoneClient client;
12 | private readonly CharacterGearDefinition definition;
13 |
14 | ///
15 | /// Constructs parser for character gear
16 | ///
17 | ///
18 | ///
19 | ///
20 | public CharacterGear(LodestoneClient client, HtmlNode rootNode, CharacterGearDefinition definition) : base(rootNode)
21 | {
22 | this.client = client;
23 | this.definition = definition;
24 | }
25 |
26 | ///
27 | /// Information about the characters' weapon. Null if none equipped.
28 | ///
29 | public GearEntry? Mainhand => new GearEntry(this.client, this.RootNode, this.definition.Mainhand).GetOptional();
30 |
31 | ///
32 | /// Information about the characters' shield/offhand. Null if none equipped.
33 | ///
34 | public GearEntry? Offhand => new GearEntry(this.client, this.RootNode, this.definition.Offhand).GetOptional();
35 |
36 | ///
37 | /// Information about the characters' headgear. Null if none equipped.
38 | ///
39 | public GearEntry? Head => new GearEntry(this.client, this.RootNode, this.definition.Head).GetOptional();
40 |
41 | ///
42 | /// Information about the characters' body gear. Null if none equipped.
43 | ///
44 | public GearEntry? Body => new GearEntry(this.client, this.RootNode, this.definition.Body).GetOptional();
45 |
46 | ///
47 | /// Information about the characters' gloves. Null if none equipped.
48 | ///
49 | public GearEntry? Hands => new GearEntry(this.client, this.RootNode, this.definition.Hands).GetOptional();
50 |
51 | ///
52 | /// Information about the characters' waist gear. Null if none equipped.
53 | ///
54 | public GearEntry? Waist => new GearEntry(this.client, this.RootNode, this.definition.Waist).GetOptional();
55 |
56 | ///
57 | /// Information about the characters' pants. Null if none equipped.
58 | ///
59 | public GearEntry? Legs => new GearEntry(this.client, this.RootNode, this.definition.Legs).GetOptional();
60 |
61 | ///
62 | /// Information about the characters' shoes. Null if none equipped.
63 | ///
64 | public GearEntry? Feet => new GearEntry(this.client, this.RootNode, this.definition.Feet).GetOptional();
65 |
66 | ///
67 | /// Information about the characters' earrings. Null if none equipped.
68 | ///
69 | public GearEntry? Earrings => new GearEntry(this.client, this.RootNode, this.definition.Earrings).GetOptional();
70 |
71 | ///
72 | /// Information about the characters' necklace. Null if none equipped.
73 | ///
74 | public GearEntry? Necklace => new GearEntry(this.client, this.RootNode, this.definition.Necklace).GetOptional();
75 |
76 | ///
77 | /// Information about the characters' bracelets. Null if none equipped.
78 | ///
79 | public GearEntry? Bracelets => new GearEntry(this.client, this.RootNode, this.definition.Bracelets).GetOptional();
80 |
81 | ///
82 | /// Information about the characters' first ring. Null if none equipped.
83 | ///
84 | public GearEntry? Ring1 => new GearEntry(this.client, this.RootNode, this.definition.Ring1).GetOptional();
85 |
86 | ///
87 | /// Information about the characters' second ring. Null if none equipped.
88 | ///
89 | public GearEntry? Ring2 => new GearEntry(this.client, this.RootNode, this.definition.Ring2).GetOptional();
90 |
91 | ///
92 | /// Information about the characters' soul crystal. Null if none equipped.
93 | ///
94 | public SoulcrystalEntry? Soulcrystal =>
95 | new SoulcrystalEntry(this.RootNode, this.definition.Soulcrystal).GetOptional();
96 | }
--------------------------------------------------------------------------------
/NetStone/Model/Parseables/Character/Gear/GearEntry.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq;
3 | using HtmlAgilityPack;
4 | using NetStone.Definitions.Model.Character;
5 | using NetStone.GameData;
6 |
7 | namespace NetStone.Model.Parseables.Character.Gear;
8 |
9 | ///
10 | /// Container class holding information about a gear slot.
11 | ///
12 | public class GearEntry : LodestoneParseable, IOptionalParseable
13 | {
14 | ///
15 | /// Character representing the high quality symbol
16 | ///
17 | public const char HqChar = '\uE03C';
18 |
19 | private readonly LodestoneClient client;
20 | private readonly GearEntryDefinition definition;
21 |
22 | private NamedGameData? cachedGameData;
23 |
24 | ///
25 | /// Construct a new gear entry
26 | ///
27 | /// Lodestone client
28 | /// Entry node
29 | /// Parser definition
30 | public GearEntry(LodestoneClient client, HtmlNode rootNode, GearEntryDefinition definition) : base(rootNode)
31 | {
32 | this.client = client;
33 | this.definition = definition;
34 | }
35 |
36 | ///
37 | /// Link to this piece's Eorzea DB page.
38 | ///
39 | public Uri? ItemDatabaseLink => ParseHref(this.definition.DbLink);
40 |
41 | ///
42 | /// Name of this item.
43 | ///
44 | public string ItemName => Parse(this.definition.Name);
45 |
46 | ///
47 | /// Indicates if this item is high quality
48 | ///
49 | public bool IsHq => this.ItemName.EndsWith(HqChar);
50 |
51 | ///
52 | /// Returns the name of this item without high quality icon
53 | ///
54 | public string StrippedItemName => this.IsHq ? this.ItemName.Remove(this.ItemName.Length - 1) : this.ItemName;
55 |
56 | ///
57 | /// Link to the glamoured item's Eorzea DB page.
58 | ///
59 | public Uri? GlamourDatabaseLink => ParseHref(this.definition.MirageDbLink);
60 |
61 | ///
62 | /// Name of the glamoured item.
63 | ///
64 | public string GlamourName => Parse(this.definition.MirageName);
65 |
66 | ///
67 | /// Name of the dye applied to this item.
68 | ///
69 | //TODO: parse
70 | public string Stain => Parse(this.definition.Stain);
71 |
72 | ///
73 | /// Materia applied to this item.
74 | ///
75 | public string[] Materia => new[]
76 | {
77 | ParseDirectInnerText(this.definition.Materia1),
78 | ParseDirectInnerText(this.definition.Materia2),
79 | ParseDirectInnerText(this.definition.Materia3),
80 | ParseDirectInnerText(this.definition.Materia4),
81 | ParseDirectInnerText(this.definition.Materia5),
82 | };
83 |
84 | ///
85 | /// Name of this item's crafter.
86 | ///
87 | public string CreatorName => Parse(this.definition.CreatorName);
88 |
89 | ///
90 | /// Item level of this item
91 | ///
92 | public int ItemLevel => int.TryParse(Parse(definition.ItemLevel).Split(' ').LastOrDefault(), out var itemLevel)
93 | ? itemLevel
94 | : 0;
95 |
96 | ///
97 | /// Indicating whether the item slot has an item equipped or not.
98 | ///
99 | public bool Exists => HasNode(this.definition.Name);
100 |
101 | ///
102 | /// Get game data representing this item
103 | ///
104 | /// Item data
105 | public NamedGameData? GetGameData()
106 | {
107 | this.cachedGameData ??= !this.Exists ? null : this.client.Data?.GetItem(this.ItemName);
108 | return this.cachedGameData;
109 | }
110 |
111 | ///
112 | /// String representation of the gear slot.
113 | ///
114 | /// The name of the item.
115 | public override string ToString() => this.ItemName;
116 | }
--------------------------------------------------------------------------------
/NetStone/Model/Parseables/Character/Gear/SoulcrystalEntry.cs:
--------------------------------------------------------------------------------
1 | using HtmlAgilityPack;
2 | using NetStone.Definitions.Model.Character;
3 | using NetStone.Search.FreeCompany;
4 | using System;
5 |
6 | namespace NetStone.Model.Parseables.Character.Gear;
7 |
8 | ///
9 | /// Represents data about a character's soul crystal
10 | ///
11 | public class SoulcrystalEntry : LodestoneParseable, IOptionalParseable
12 | {
13 | private readonly SoulcrystalEntryDefinition definition;
14 |
15 | ///
16 | public SoulcrystalEntry(HtmlNode rootNode, SoulcrystalEntryDefinition definition) : base(rootNode)
17 | {
18 | this.definition = definition;
19 | }
20 |
21 | //public Uri ItemDatabaseLink => ParseHref(this.definition.Name);
22 |
23 | ///
24 | /// Name of the item
25 | ///
26 | public string ItemName => Parse(this.definition.Name);
27 |
28 | ///
29 | public bool Exists => HasNode(this.definition.Name);
30 |
31 | ///
32 | public override string ToString() => this.ItemName;
33 | }
--------------------------------------------------------------------------------
/NetStone/Model/Parseables/FreeCompany/FreeCompanyEstate.cs:
--------------------------------------------------------------------------------
1 | using HtmlAgilityPack;
2 | using NetStone.Definitions.Model.FreeCompany;
3 |
4 | namespace NetStone.Model.Parseables.FreeCompany;
5 |
6 | ///
7 | /// Information about the Free CCompany's estate
8 | ///
9 | public class FreeCompanyEstate : LodestoneParseable, IOptionalParseable
10 | {
11 | private readonly EstateDefinition definition;
12 |
13 | ///
14 | public FreeCompanyEstate(HtmlNode rootNode, EstateDefinition definition) : base(rootNode)
15 | {
16 | this.definition = definition;
17 | }
18 |
19 | ///
20 | /// Name of the estate
21 | ///
22 | public string Name => Parse(this.definition.Name);
23 |
24 | ///
25 | /// The greeting phrase for this estate
26 | ///
27 | public string Greeting => Parse(this.definition.Greeting);
28 |
29 | ///
30 | /// The plot where the estate is built
31 | ///
32 | public string Plot => Parse(this.definition.Plot);
33 |
34 | ///
35 | public bool Exists => !HasNode(this.definition.NoEstate);
36 | }
--------------------------------------------------------------------------------
/NetStone/Model/Parseables/FreeCompany/FreeCompanyFocus.cs:
--------------------------------------------------------------------------------
1 | using HtmlAgilityPack;
2 | using NetStone.Definitions.Model.FreeCompany;
3 |
4 | namespace NetStone.Model.Parseables.FreeCompany;
5 |
6 | ///
7 | /// Infomation about the content this FC focuses on
8 | ///
9 | public class FreeCompanyFocus : LodestoneParseable, IOptionalParseable
10 | {
11 | private readonly FreeCompanyFocusDefinition definition;
12 |
13 | ///
14 | public FreeCompanyFocus(HtmlNode rootNode, FreeCompanyFocusDefinition definition) : base(rootNode)
15 | {
16 | this.definition = definition;
17 | }
18 |
19 | ///
20 | /// Indicates that this FC has specified a focus
21 | ///
22 | public bool HasFocus => !HasNode(this.definition.NOTSPECIFIED);
23 |
24 | ///
25 | public bool Exists => this.HasFocus;
26 |
27 | ///
28 | /// Entry for this FC's focus on role play
29 | ///
30 | public FreeCompanyFocusEntry RolePlay => new(this.RootNode, this.definition.RolePlay);
31 |
32 | ///
33 | /// Entry for this FC's focus on leveling
34 | ///
35 | public FreeCompanyFocusEntry Leveling => new(this.RootNode, this.definition.Leveling);
36 |
37 | ///
38 | /// Entry for this FC's focus on casual content
39 | ///
40 | public FreeCompanyFocusEntry Casual => new(this.RootNode, this.definition.Casual);
41 |
42 | ///
43 | /// Entry for this FC's focus on hardcore content
44 | ///
45 | public FreeCompanyFocusEntry Hardcore => new(this.RootNode, this.definition.Hardcore);
46 |
47 | ///
48 | /// Entry for this FC's focus on dungeons
49 | ///
50 | public FreeCompanyFocusEntry Dungeons => new(this.RootNode, this.definition.Dungeons);
51 |
52 | ///
53 | /// Entry for this FC's focus on guild heists
54 | ///
55 | public FreeCompanyFocusEntry Guildhests => new(this.RootNode, this.definition.Guildhests);
56 |
57 | ///
58 | /// Entry for this FC's focus on trials
59 | ///
60 | public FreeCompanyFocusEntry Trials => new(this.RootNode, this.definition.Trials);
61 |
62 | ///
63 | /// Entry for this FC's focus on raiding
64 | ///
65 | public FreeCompanyFocusEntry Raids => new(this.RootNode, this.definition.Raids);
66 |
67 | ///
68 | /// Entry for this FC's focus on PvP
69 | ///
70 | public FreeCompanyFocusEntry PvP => new(this.RootNode, this.definition.PvP);
71 | }
--------------------------------------------------------------------------------
/NetStone/Model/Parseables/FreeCompany/FreeCompanyFocusEntry.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using HtmlAgilityPack;
3 | using NetStone.Definitions.Model.FreeCompany;
4 |
5 | namespace NetStone.Model.Parseables.FreeCompany;
6 |
7 | ///
8 | /// Data about one type of Free Company focus
9 | ///
10 | public class FreeCompanyFocusEntry : LodestoneParseable
11 | {
12 | private readonly FreeCompanyFocusEntryDefinition definition;
13 |
14 | ///
15 | /// Construct instance to parse focus
16 | ///
17 | /// Node that contains relevant data
18 | /// Parse definition
19 | public FreeCompanyFocusEntry(HtmlNode rootNode, FreeCompanyFocusEntryDefinition definition) : base(rootNode)
20 | {
21 | this.definition = definition;
22 | }
23 |
24 | ///
25 | /// Name of the focus type
26 | ///
27 | public string Name => Parse(this.definition.NAME);
28 |
29 | ///
30 | /// Uri to icon
31 | ///
32 | public Uri? Icon => ParseImageSource(this.definition.ICON);
33 |
34 | ///
35 | /// Indicates this focus is selected
36 | ///
37 | public bool IsEnabled => string.IsNullOrEmpty(Parse(this.definition.STATUS));
38 | }
--------------------------------------------------------------------------------
/NetStone/Model/Parseables/FreeCompany/FreeCompanyReputation.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Diagnostics;
4 | using HtmlAgilityPack;
5 | using NetStone.Definitions.Model.FreeCompany;
6 | using NetStone.StaticData;
7 |
8 | namespace NetStone.Model.Parseables.FreeCompany;
9 |
10 | ///
11 | /// Information on free companies
12 | ///
13 | public class FreeCompanyReputation : LodestoneParseable
14 | {
15 | private readonly FreeCompanyReputationDefinition definition;
16 |
17 | ///
18 | /// Creates Free Company reputation information
19 | ///
20 | ///
21 | ///
22 | public FreeCompanyReputation(HtmlNode rootNode, FreeCompanyReputationDefinition definition) : base(rootNode)
23 | {
24 | this.definition = definition;
25 | }
26 |
27 | ///
28 | /// Maelstrom
29 | ///
30 | public FreeCompanyReputationEntry Maelstrom => new(this.RootNode, this.definition.Maelstrom);
31 |
32 | ///
33 | /// Order of the Twin Adder
34 | ///
35 | public FreeCompanyReputationEntry Adders => new(this.RootNode, this.definition.Adders);
36 |
37 | ///
38 | /// Immortal Flames
39 | ///
40 | public FreeCompanyReputationEntry Flames => new(this.RootNode, this.definition.Flames);
41 |
42 | ///
43 | /// Returns the relevant .
44 | ///
45 | /// Grand Company
46 | /// Grand company reputation
47 | public FreeCompanyReputationEntry GrandCompanyRep(GrandCompany gc) => gc switch
48 | {
49 | GrandCompany.Maelstrom => this.Maelstrom,
50 | GrandCompany.OrderOfTheTwinAdder => this.Adders,
51 | GrandCompany.ImmortalFlames => this.Flames,
52 | _ => throw new ArgumentException("Unknown Grand Company"),
53 | };
54 |
55 | ///
56 | /// Maps to .
57 | /// You should only access this once and store a reference.
58 | ///
59 | public Dictionary GrandCompanyDict =>
60 | new()
61 | {
62 | { GrandCompany.Maelstrom, this.Maelstrom },
63 | { GrandCompany.OrderOfTheTwinAdder, this.Adders },
64 | { GrandCompany.ImmortalFlames, this.Flames },
65 | };
66 | }
--------------------------------------------------------------------------------
/NetStone/Model/Parseables/FreeCompany/FreeCompanyReputationEntry.cs:
--------------------------------------------------------------------------------
1 | using HtmlAgilityPack;
2 | using NetStone.Definitions.Model.FreeCompany;
3 |
4 | namespace NetStone.Model.Parseables.FreeCompany;
5 |
6 | ///
7 | /// Models reputation of a Free Company with on Grand Company
8 | ///
9 | public class FreeCompanyReputationEntry : LodestoneParseable
10 | {
11 | private readonly FreeCompanyReputationEntryDefinition definition;
12 |
13 | ///
14 | /// Constructs FC reputation with on GC
15 | ///
16 | ///
17 | ///
18 | public FreeCompanyReputationEntry(HtmlNode rootNode, FreeCompanyReputationEntryDefinition definition) :
19 | base(rootNode)
20 | {
21 | this.definition = definition;
22 | }
23 |
24 | ///
25 | /// Name of the Grand Company
26 | ///
27 | public string Name => Parse(this.definition.Name);
28 |
29 | ///
30 | /// Progress to next rank
31 | ///
32 | public int Progress => int.Parse(Parse(this.definition.Progress));
33 |
34 | ///
35 | /// Current rank
36 | ///
37 | public string Rank => Parse(this.definition.Rank);
38 | }
--------------------------------------------------------------------------------
/NetStone/Model/Parseables/FreeCompany/LodestoneFreeCompany.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Threading.Tasks;
3 | using HtmlAgilityPack;
4 | using NetStone.Definitions;
5 | using NetStone.Definitions.Model.FreeCompany;
6 | using NetStone.Model.Parseables.FreeCompany.Members;
7 | using NetStone.Search.FreeCompany;
8 |
9 | namespace NetStone.Model.Parseables.FreeCompany;
10 |
11 | ///
12 | /// Provides information of a Free Company
13 | ///
14 | public class LodestoneFreeCompany : LodestoneParseable
15 | {
16 | private readonly LodestoneClient client;
17 |
18 | private readonly FreeCompanyDefinition fcDefinition;
19 | private readonly FreeCompanyFocusDefinition focusDefinition;
20 | private readonly FreeCompanyReputationDefinition reputationDefinition;
21 |
22 | ///
23 | /// Constructs Free Company information parser
24 | ///
25 | /// Current client
26 | /// Root node of FC page
27 | /// Parser definitions
28 | /// Id of FC
29 | public LodestoneFreeCompany(LodestoneClient client, HtmlNode rootNode, DefinitionsContainer definitions, string id)
30 | : base(rootNode)
31 | {
32 | this.client = client;
33 | this.Id = id;
34 |
35 | this.fcDefinition = definitions.FreeCompany;
36 | this.focusDefinition = definitions.FreeCompanyFocus;
37 | this.reputationDefinition = definitions.FreeCompanyReputation;
38 | }
39 |
40 | ///
41 | /// Name of this FC
42 | ///
43 | public string Name => Parse(this.fcDefinition.Name);
44 |
45 | ///
46 | /// Id of this FC
47 | ///
48 | public string Id { get; }
49 |
50 | ///
51 | /// Slogan
52 | ///
53 | public string Slogan => Parse(this.fcDefinition.Slogan);
54 |
55 | ///
56 | /// Tag
57 | ///
58 | public string Tag => Parse(this.fcDefinition.Tag);
59 |
60 | ///
61 | /// FC Icon/Crest
62 | ///
63 | public IconLayers CrestLayers => new(this.RootNode, this.fcDefinition.CrestLayers);
64 |
65 | ///
66 | /// Formation date
67 | ///
68 | public DateTime Formed => ParseTime(this.fcDefinition.Formed);
69 |
70 | ///
71 | /// Current GC
72 | ///
73 | public string GrandCompany => Parse(this.fcDefinition.GrandCompany).TrimEnd();
74 |
75 | ///
76 | /// Current Rank
77 | ///
78 | public int Rank => int.Parse(Parse(this.fcDefinition.Rank));
79 |
80 | ///
81 | /// Monthly ranking
82 | ///
83 | public int? RankingMonthly => int.TryParse(Parse(this.fcDefinition.Ranking.Monthly), out var result) ? result : null;
84 |
85 | ///
86 | /// Weekly ranking
87 | ///
88 | public int? RankingWeekly => int.TryParse(Parse(this.fcDefinition.Ranking.Weekly), out var result) ? result : null;
89 |
90 | ///
91 | /// Recruitment status
92 | ///
93 | public string Recruitment => Parse(this.fcDefinition.Recruitment);
94 |
95 | ///
96 | /// Number of active members
97 | ///
98 | public int ActiveMemberCount => int.Parse(Parse(this.fcDefinition.ActiveMemberCount));
99 |
100 | ///
101 | /// Activity status
102 | ///
103 | //todo: selector does not work
104 | public string ActiveState => Parse(this.fcDefinition.Activestate).Trim();
105 |
106 |
107 | ///
108 | /// Information about the estate
109 | ///
110 | public FreeCompanyEstate? Estate =>
111 | new FreeCompanyEstate(this.RootNode, this.fcDefinition.EstateDefinition).GetOptional();
112 |
113 | ///
114 | /// Information about focused gameplay
115 | ///
116 | public FreeCompanyFocus? Focus => new FreeCompanyFocus(this.RootNode, this.focusDefinition).GetOptional();
117 |
118 | ///
119 | /// Reputation with the Grand Companies
120 | ///
121 | public FreeCompanyReputation Reputation => new(this.RootNode, this.reputationDefinition);
122 |
123 | ///
124 | /// Home World
125 | ///
126 | public string World => Parse(this.fcDefinition.Server);
127 |
128 | ///
129 | /// Fetches all members of this FC
130 | ///
131 | /// Members
132 | public async Task GetMembers() => await this.client.GetFreeCompanyMembers(this.Id);
133 | }
--------------------------------------------------------------------------------
/NetStone/Model/Parseables/FreeCompany/Members/FreeCompanyMembers.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using HtmlAgilityPack;
3 | using NetStone.Definitions.Model;
4 | using NetStone.Definitions.Model.FreeCompany;
5 |
6 | namespace NetStone.Model.Parseables.FreeCompany.Members;
7 |
8 | ///
9 | /// Information about a Free Company's members
10 | ///
11 | public class FreeCompanyMembers : PaginatedIdResult
12 | {
13 | ///
14 | /// Constructs member list
15 | ///
16 | ///
17 | ///
18 | ///
19 | ///
20 | public FreeCompanyMembers(LodestoneClient client, HtmlNode rootNode, PagedDefinition definition, string id) :
21 | base(rootNode, definition, client.GetFreeCompanyMembers, id)
22 | {
23 | }
24 |
25 | ///
26 | /// Lists all members
27 | ///
28 | public IEnumerable Members => this.Results;
29 |
30 | ///
31 | protected override FreeCompanyMembersEntry[] ParseResults()
32 | {
33 | var nodes = QueryContainer(this.PageDefinition);
34 |
35 | var parsedResults = new FreeCompanyMembersEntry[nodes.Length];
36 | for (var i = 0; i < parsedResults.Length; i++)
37 | {
38 | parsedResults[i] = new FreeCompanyMembersEntry(nodes[i], this.PageDefinition.Entry);
39 | }
40 | return parsedResults;
41 | }
42 | }
--------------------------------------------------------------------------------
/NetStone/Model/Parseables/FreeCompany/Members/FreeCompanyMembersEntry.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using HtmlAgilityPack;
3 | using NetStone.Definitions.Model.FreeCompany;
4 |
5 | namespace NetStone.Model.Parseables.FreeCompany.Members;
6 |
7 | ///
8 | /// Models one entry for the Free Company member list
9 | ///
10 | public class FreeCompanyMembersEntry : LodestoneParseable
11 | {
12 | private readonly FreeCompanyMembersEntryDefinition definition;
13 |
14 | ///
15 | public FreeCompanyMembersEntry(HtmlNode rootNode, FreeCompanyMembersEntryDefinition definition) : base(rootNode)
16 | {
17 | this.definition = definition;
18 | }
19 |
20 | ///
21 | /// Name of character
22 | ///
23 | public string Name => Parse(this.definition.Name);
24 |
25 | ///
26 | /// Id of character
27 | ///
28 | public string Id => Parse(this.definition.Id);
29 |
30 | ///
31 | /// Rank with character's Grand Company
32 | ///
33 | public string Rank => Parse(this.definition.Rank);
34 |
35 | ///
36 | /// Icon representing
37 | ///
38 | public Uri? RankIcon => ParseImageSource(this.definition.RankIcon);
39 |
40 | ///
41 | /// Rank with character's Free Company
42 | ///
43 | public string FreeCompanyRank => Parse(this.definition.FreeCompanyRank);
44 |
45 | ///
46 | /// Icon representing
47 | ///
48 | public Uri? FreeCompanyRankIcon => ParseImageSource(this.definition.FreeCompanyRankIcon);
49 |
50 | ///
51 | /// Home world
52 | ///
53 | public string Server => ParseRegex(this.definition.Server)["World"].Value;
54 |
55 | ///
56 | /// Data center
57 | ///
58 | public string Datacenter => ParseRegex(this.definition.Server)["DC"].Value;
59 |
60 | ///
61 | /// Character's avatar
62 | ///
63 | public Uri? Avatar => ParseImageSource(this.definition.Avatar);
64 | }
--------------------------------------------------------------------------------
/NetStone/Model/Parseables/IconLayers.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using HtmlAgilityPack;
3 | using NetStone.Definitions.Model;
4 |
5 | namespace NetStone.Model.Parseables;
6 |
7 | ///
8 | /// Container class holding information about a social group's icon.
9 | ///
10 | public class IconLayers : LodestoneParseable
11 | {
12 | private readonly IconLayersDefinition definition;
13 |
14 | ///
15 | public IconLayers(HtmlNode rootNode, IconLayersDefinition definition) : base(rootNode)
16 | {
17 | this.definition = definition;
18 | }
19 |
20 | ///
21 | /// Link to the top layer image of the icon.
22 | ///
23 | public Uri? TopLayer => ParseImageSource(this.definition.Top);
24 |
25 | ///
26 | /// Link to the top layer image of the icon.
27 | ///
28 | public Uri? MiddleLayer => ParseImageSource(this.definition.Middle);
29 |
30 | ///
31 | /// Link to the top layer image of the icon.
32 | ///
33 | public Uri? BottomLayer => ParseImageSource(this.definition.Bottom);
34 | }
--------------------------------------------------------------------------------
/NetStone/Model/Parseables/Linkshell/LodestoneLinkshell.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using HtmlAgilityPack;
3 | using NetStone.Definitions;
4 | using NetStone.Definitions.Model.Linkshell;
5 | using NetStone.Model.Parseables.Linkshell.Members;
6 |
7 | namespace NetStone.Model.Parseables.Linkshell;
8 |
9 | ///
10 | /// Container class holding information about a linkshell and it's members.
11 | ///
12 | public class LodestoneLinkshell : PaginatedIdResult
13 | {
14 | private readonly LinkshellDefinition lsDefinition;
15 |
16 | ///
17 | /// Container class for a parseable linkshell page.
18 | ///
19 | /// The to be used to fetch further information.
20 | /// The root document node of the page.
21 | /// The holding definitions to be used to access data.
22 | /// The ID of the cross world linkshell.
23 | public LodestoneLinkshell(LodestoneClient client, HtmlNode rootNode, DefinitionsContainer container, string id) : base(rootNode,container.LinkshellMember, client.GetLinkshell,id)
24 | {
25 | this.lsDefinition = container.Linkshell;
26 | }
27 |
28 | ///
29 | /// Name
30 | ///
31 | public string Name => Parse(this.lsDefinition.Name);
32 |
33 | ///
34 | /// List of members
35 | ///
36 | public IEnumerable Members => this.Results;
37 |
38 | ///
39 | protected override LinkshellMemberEntry[] ParseResults()
40 | {
41 | var nodes = QueryContainer(this.PageDefinition);
42 |
43 | var parsedResults = new LinkshellMemberEntry[nodes.Length];
44 | for (var i = 0; i < parsedResults.Length; i++)
45 | {
46 | parsedResults[i] = new LinkshellMemberEntry(nodes[i], this.PageDefinition.Entry);
47 | }
48 | return parsedResults;
49 | }
50 | }
--------------------------------------------------------------------------------
/NetStone/Model/Parseables/Linkshell/Members/LinkshellMemberEntry.cs:
--------------------------------------------------------------------------------
1 | using HtmlAgilityPack;
2 | using NetStone.Definitions.Model.Linkshell;
3 |
4 | namespace NetStone.Model.Parseables.Linkshell.Members;
5 |
6 | ///
7 | /// Container class holding information about a linkshell member.
8 | ///
9 | public class LinkshellMemberEntry : LodestoneParseable
10 | {
11 | private readonly LinkshellMemberEntryDefinition definition;
12 | ///
13 | /// Create instance of member entry for a given node
14 | ///
15 | /// Root html node of this entry
16 | /// Css and regex definition
17 | public LinkshellMemberEntry(HtmlNode rootNode, LinkshellMemberEntryDefinition definition) : base(rootNode)
18 | {
19 | this.definition = definition;
20 | }
21 |
22 | ///
23 | /// Avatar
24 | ///
25 | public string Avatar => Parse(this.definition.Avatar);
26 |
27 | ///
28 | /// ID
29 | ///
30 | public string? Id => ParseHrefId(this.definition.Id);
31 |
32 | ///
33 | /// Name
34 | ///
35 | public string Name => Parse(this.definition.Name);
36 |
37 | ///
38 | /// Rank
39 | ///
40 | public string Rank => Parse(this.definition.Rank);
41 |
42 | ///
43 | /// Rank Icon
44 | ///
45 | public string RankIcon => Parse(this.definition.RankIcon);
46 |
47 | ///
48 | /// Linkshell rank
49 | ///
50 | public string LinkshellRank => Parse(this.definition.LinkshellRank);
51 |
52 | ///
53 | /// Linkshell rank Icon
54 | ///
55 | public string LinkshellRankIcon => Parse(this.definition.LinkshellRankIcon);
56 |
57 | ///
58 | /// Server
59 | ///
60 | public string Server => Parse(this.definition.Server);
61 | }
--------------------------------------------------------------------------------
/NetStone/Model/Parseables/Search/CWLS/CrossworldLinkshellSearchEntry.cs:
--------------------------------------------------------------------------------
1 | using System.Threading.Tasks;
2 | using HtmlAgilityPack;
3 | using NetStone.Definitions.Model.CWLS;
4 | using NetStone.Model.Parseables.CWLS;
5 |
6 | namespace NetStone.Model.Parseables.Search.CWLS;
7 |
8 | ///
9 | /// Models one entry in the cwls search results list
10 | ///
11 | public class CrossworldLinkshellSearchEntry : LodestoneParseable
12 | {
13 | private readonly LodestoneClient client;
14 | private readonly CrossworldLinkshellSearchEntryDefinition definition;
15 |
16 | ///
17 | public CrossworldLinkshellSearchEntry(LodestoneClient client, HtmlNode rootNode, CrossworldLinkshellSearchEntryDefinition definition) :
18 | base(rootNode)
19 | {
20 | this.client = client;
21 | this.definition = definition;
22 | }
23 |
24 | ///
25 | /// Character name
26 | ///
27 | public string Name => Parse(this.definition.Name);
28 |
29 | ///
30 | /// Lodestone Id
31 | ///
32 | public string? Id => ParseHrefId(this.definition.Id);
33 |
34 | ///
35 | /// Datacenter
36 | ///
37 | public string DataCenter => Parse(this.definition.Dc);
38 |
39 |
40 | ///
41 | /// Number of active members
42 | ///
43 | public int ActiveMembers => int.TryParse(Parse(this.definition.ActiveMembers), out var parsed) ? parsed : -1;
44 |
45 | ///
46 | /// Fetch cross world link shell
47 | ///
48 | /// Task of retrieving cwls
49 | public async Task GetCrossworldLinkshell() =>
50 | this.Id is null ? null : await this.client.GetCrossworldLinkshell(this.Id);
51 |
52 | ///
53 | public override string ToString() => this.Name;
54 | }
--------------------------------------------------------------------------------
/NetStone/Model/Parseables/Search/CWLS/CrossworldLinkshellSearchPage.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using HtmlAgilityPack;
3 | using NetStone.Definitions.Model;
4 | using NetStone.Definitions.Model.CWLS;
5 | using NetStone.Search.Linkshell;
6 |
7 | namespace NetStone.Model.Parseables.Search.CWLS;
8 |
9 | ///
10 | /// Models cross world link shell search results
11 | ///
12 | public class CrossworldLinkshellSearchPage
13 | : PaginatedSearchResult
15 | {
16 | private readonly LodestoneClient client;
17 | ///
18 | /// Constructs character search results
19 | ///
20 | ///
21 | ///
22 | ///
23 | ///
24 | public CrossworldLinkshellSearchPage(LodestoneClient client, HtmlNode rootNode,
25 | PagedDefinition pageDefinition,
26 | CrossworldLinkshellSearchQuery currentQuery)
27 | : base(rootNode, pageDefinition, client.SearchCrossworldLinkshell, currentQuery)
28 | {
29 | this.client = client;
30 | }
31 |
32 |
33 | ///
34 | /// List all results
35 | ///
36 | public new IEnumerable Results => base.Results;
37 |
38 | ///
39 | protected override CrossworldLinkshellSearchEntry[] ParseResults()
40 | {
41 | var container = QueryContainer(this.PageDefinition);
42 |
43 | var parsedResults = new CrossworldLinkshellSearchEntry[container.Length];
44 | for (var i = 0; i < parsedResults.Length; i++)
45 | {
46 | parsedResults[i] = new CrossworldLinkshellSearchEntry(this.client, container[i], this.PageDefinition.Entry);
47 | }
48 | return parsedResults;
49 | }
50 | }
--------------------------------------------------------------------------------
/NetStone/Model/Parseables/Search/Character/CharacterSearchEntry.cs:
--------------------------------------------------------------------------------
1 | using System.Threading.Tasks;
2 | using HtmlAgilityPack;
3 | using NetStone.Definitions.Model.Character;
4 | using NetStone.Model.Parseables.Character;
5 |
6 | namespace NetStone.Model.Parseables.Search.Character;
7 |
8 | ///
9 | /// Models one entry in the character search results list
10 | ///
11 | public class CharacterSearchEntry : LodestoneParseable
12 | {
13 | private readonly LodestoneClient client;
14 | private readonly CharacterSearchEntryDefinition definition;
15 |
16 | ///
17 | public CharacterSearchEntry(LodestoneClient client, HtmlNode rootNode, CharacterSearchEntryDefinition definition) :
18 | base(rootNode)
19 | {
20 | this.client = client;
21 | this.definition = definition;
22 | }
23 |
24 | ///
25 | /// Character name
26 | ///
27 | public string Name => Parse(this.definition.Name);
28 |
29 | ///
30 | /// Lodestone Id
31 | ///
32 | public string? Id => ParseHrefId(this.definition.Id);
33 |
34 | ///
35 | /// Fetch character profile
36 | ///
37 | /// Task of retrieving character
38 | public async Task GetCharacter() =>
39 | this.Id is null ? null : await this.client.GetCharacter(this.Id);
40 |
41 | ///
42 | public override string ToString() => this.Name;
43 | }
--------------------------------------------------------------------------------
/NetStone/Model/Parseables/Search/Character/CharacterSearchPage.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using HtmlAgilityPack;
3 | using NetStone.Definitions.Model;
4 | using NetStone.Definitions.Model.Character;
5 | using NetStone.Search.Character;
6 |
7 | namespace NetStone.Model.Parseables.Search.Character;
8 |
9 | ///
10 | /// Models character search results
11 | ///
12 | public class CharacterSearchPage : PaginatedSearchResult
14 | {
15 | private readonly LodestoneClient client;
16 |
17 | ///
18 | /// Constructs character search results
19 | ///
20 | ///
21 | ///
22 | ///
23 | ///
24 | public CharacterSearchPage(LodestoneClient client, HtmlNode rootNode,
25 | PagedDefinition pageDefinition,
26 | CharacterSearchQuery currentQuery)
27 | : base(rootNode, pageDefinition, client.SearchCharacter, currentQuery)
28 | {
29 | this.client = client;
30 | }
31 |
32 | ///
33 | /// List all results
34 | ///
35 | public new IEnumerable Results => base.Results;
36 |
37 | ///
38 | protected override CharacterSearchEntry[] ParseResults()
39 | {
40 | var container = QueryContainer(this.PageDefinition);
41 |
42 | var parsedResults = new CharacterSearchEntry[container.Length];
43 | for (var i = 0; i < parsedResults.Length; i++)
44 | {
45 | parsedResults[i] = new CharacterSearchEntry(this.client, container[i], this.PageDefinition.Entry);
46 | }
47 |
48 | return parsedResults;
49 | }
50 | }
--------------------------------------------------------------------------------
/NetStone/Model/Parseables/Search/FreeCompany/FreeCompanySearchEntry.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Threading.Tasks;
3 | using HtmlAgilityPack;
4 | using NetStone.Definitions.Model.FreeCompany;
5 | using NetStone.Model.Parseables.FreeCompany;
6 | using NetStone.Search.FreeCompany;
7 |
8 | namespace NetStone.Model.Parseables.Search.FreeCompany;
9 |
10 | ///
11 | /// Models on entry of the free company search results
12 | ///
13 | public class FreeCompanySearchEntry : LodestoneParseable
14 | {
15 | private readonly LodestoneClient client;
16 | private readonly FreeCompanySearchEntryDefinition definition;
17 |
18 | ///
19 | public FreeCompanySearchEntry(LodestoneClient client, HtmlNode rootNode,
20 | FreeCompanySearchEntryDefinition definition) : base(rootNode)
21 | {
22 | this.client = client;
23 | this.definition = definition;
24 | }
25 |
26 | ///
27 | /// Free Company name
28 | ///
29 | public string Name => Parse(this.definition.Name);
30 |
31 | ///
32 | /// Free company Id
33 | ///
34 | public string? Id => ParseHrefId(this.definition.Id);
35 |
36 | ///
37 | /// Home world of the FC
38 | ///
39 | public string Server => ParseRegex(this.definition.Server)["World"].Value;
40 |
41 | ///
42 | /// Data center of the FC
43 | ///
44 | public string Datacenter => ParseRegex(this.definition.Server)["DC"].Value;
45 |
46 | ///
47 | /// FC crest/icon
48 | ///
49 | public IconLayers CrestLayers => new(this.RootNode, this.definition.CrestLayers);
50 |
51 | ///
52 | /// Formation date
53 | ///
54 | public DateTime Formed => ParseTime(this.definition.Formed);
55 |
56 | ///
57 | /// Active status
58 | ///
59 | public ActiveTimes Active => this.ActiveText switch
60 | {
61 | "Always" => ActiveTimes.Always,
62 | "Weekends" => ActiveTimes.WeekendsOnly,
63 | "Weekdays" => ActiveTimes.WeekdaysOnly,
64 | "Not specified" => ActiveTimes.All,
65 | { } s => throw new ArgumentOutOfRangeException(s),
66 | };
67 |
68 | ///
69 | /// Full text of active times
70 | ///
71 | //ToDo: fix regex
72 | public string ActiveText => ParseInnerText(this.definition.Active)[8..];
73 |
74 | ///
75 | /// Active member count
76 | ///
77 | public int ActiveMembers => int.Parse(Parse(this.definition.ActiveMembers));
78 |
79 | ///
80 | /// Recruitment status
81 | ///
82 | public bool RecruitmentOpen => Parse(this.definition.RecruitmentOpen) == "Open";
83 |
84 | ///
85 | /// Affiliated grand company
86 | ///
87 | public string GrandCompany => Parse(this.definition.GrandCompany);
88 |
89 | ///
90 | /// Estate status
91 | ///
92 | public Housing EstateBuild => Parse(this.definition.EstateBuilt) switch
93 | {
94 | "No Estate or Plot" => Housing.NoEstateOrPlot,
95 | "Estate Built" => Housing.EstateBuilt,
96 | "Plot Only" => Housing.PlotOnly,
97 | _ => throw new ArgumentOutOfRangeException(),
98 | };
99 |
100 | ///
101 | /// Retrieve Free Company profile
102 | ///
103 | /// Full FC profile
104 | public async Task GetFreeCompany() =>
105 | this.Id is null ? null : await this.client.GetFreeCompany(this.Id);
106 |
107 | ///
108 | public override string ToString() => this.Name;
109 | }
--------------------------------------------------------------------------------
/NetStone/Model/Parseables/Search/FreeCompany/FreeCompanySearchPage.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using HtmlAgilityPack;
3 | using NetStone.Definitions.Model;
4 | using NetStone.Definitions.Model.FreeCompany;
5 | using NetStone.Search.FreeCompany;
6 |
7 | namespace NetStone.Model.Parseables.Search.FreeCompany;
8 |
9 | ///
10 | /// Models Free Company search results
11 | ///
12 | public class FreeCompanySearchPage : PaginatedSearchResult
14 | {
15 | private readonly LodestoneClient client;
16 |
17 | ///
18 | /// Constructs Free Company Search results
19 | ///
20 | ///
21 | ///
22 | ///
23 | ///
24 | public FreeCompanySearchPage(LodestoneClient client, HtmlNode rootNode,
25 | PagedDefinition pageDefinition,
26 | FreeCompanySearchQuery currentQuery)
27 | : base(rootNode, pageDefinition, client.SearchFreeCompany, currentQuery)
28 | {
29 | this.client = client;
30 | }
31 |
32 | ///
33 | /// Lists all search results
34 | ///
35 | public new IEnumerable Results => base.Results;
36 |
37 | ///
38 | protected override FreeCompanySearchEntry[] ParseResults()
39 | {
40 | var container = QueryContainer(this.PageDefinition);
41 |
42 | var parsedResults = new FreeCompanySearchEntry[container.Length];
43 | for (var i = 0; i < parsedResults.Length; i++)
44 | {
45 | parsedResults[i] = new FreeCompanySearchEntry(this.client, container[i], this.PageDefinition.Entry);
46 | }
47 | return parsedResults;
48 | }
49 | }
--------------------------------------------------------------------------------
/NetStone/Model/Parseables/Search/Linkshell/LinkshellSearchEntry.cs:
--------------------------------------------------------------------------------
1 | using System.Threading.Tasks;
2 | using HtmlAgilityPack;
3 | using NetStone.Definitions.Model.Linkshell;
4 | using NetStone.Model.Parseables.Linkshell;
5 |
6 | namespace NetStone.Model.Parseables.Search.Linkshell;
7 |
8 | ///
9 | /// Models one entry in the linkshell search results list
10 | ///
11 | public class LinkshellSearchEntry : LodestoneParseable
12 | {
13 | private readonly LodestoneClient client;
14 | private readonly LinkshellSearchEntryDefinition definition;
15 |
16 | ///
17 | public LinkshellSearchEntry(LodestoneClient client, HtmlNode rootNode, LinkshellSearchEntryDefinition definition) :
18 | base(rootNode)
19 | {
20 | this.client = client;
21 | this.definition = definition;
22 | }
23 |
24 | ///
25 | /// Character name
26 | ///
27 | public string Name => Parse(this.definition.Name);
28 |
29 | ///
30 | /// Lodestone Id
31 | ///
32 | public string? Id => ParseHrefId(this.definition.Id);
33 |
34 | ///
35 | /// Homeworld / Server
36 | ///
37 | public string HomeWorld => Parse(this.definition.Server);
38 |
39 | ///
40 | /// Number of active members
41 | ///
42 | public int ActiveMembers => int.TryParse(Parse(this.definition.ActiveMembers), out var parsed) ? parsed : -1;
43 |
44 | ///
45 | /// Fetch character profile
46 | ///
47 | /// Task of retrieving character
48 | public async Task GetLinkshell() =>
49 | this.Id is null ? null : await this.client.GetLinkshell(this.Id);
50 |
51 | ///
52 | public override string ToString() => this.Name;
53 | }
--------------------------------------------------------------------------------
/NetStone/Model/Parseables/Search/Linkshell/LinkshellSearchPage.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using HtmlAgilityPack;
3 | using NetStone.Definitions.Model;
4 | using NetStone.Definitions.Model.Linkshell;
5 | using NetStone.Search.Linkshell;
6 |
7 | namespace NetStone.Model.Parseables.Search.Linkshell;
8 |
9 | ///
10 | /// Models link shell search results
11 | ///
12 | public class LinkshellSearchPage : PaginatedSearchResult
14 | {
15 | private readonly LodestoneClient client;
16 |
17 | ///
18 | /// Constructs character search results
19 | ///
20 | ///
21 | ///
22 | ///
23 | ///
24 | public LinkshellSearchPage(LodestoneClient client, HtmlNode rootNode,
25 | PagedDefinition pageDefinition,
26 | LinkshellSearchQuery currentQuery)
27 | : base(rootNode, pageDefinition, client.SearchLinkshell, currentQuery)
28 | {
29 | this.client = client;
30 | }
31 |
32 | ///
33 | /// List all results
34 | ///
35 | public new IEnumerable Results => base.Results;
36 |
37 | ///
38 | protected override LinkshellSearchEntry[] ParseResults()
39 | {
40 | var container = QueryContainer(this.PageDefinition);
41 |
42 | var parsedResults = new LinkshellSearchEntry[container.Length];
43 | for (var i = 0; i < parsedResults.Length; i++)
44 | {
45 | parsedResults[i] = new LinkshellSearchEntry(this.client, container[i], this.PageDefinition.Entry);
46 | }
47 | return parsedResults;
48 | }
49 | }
--------------------------------------------------------------------------------
/NetStone/Model/Parseables/SocialGroup.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using HtmlAgilityPack;
3 | using NetStone.Definitions.Model.Character;
4 |
5 | namespace NetStone.Model.Parseables;
6 |
7 | ///
8 | /// Models a group of players/characters
9 | ///
10 | public class SocialGroup : LodestoneParseable, IOptionalParseable
11 | {
12 | private readonly ICharacterSocialGroupDefinition definition;
13 |
14 | ///
15 | public SocialGroup(HtmlNode rootNode, ICharacterSocialGroupDefinition socialGroupDefinition) : base(rootNode)
16 | {
17 | this.definition = socialGroupDefinition;
18 | }
19 |
20 | ///
21 | /// Indicating whether this social group exists or not.
22 | ///
23 | public bool Exists => this.Id != null;
24 |
25 | ///
26 | /// Name of this social group.
27 | ///
28 | public string Name => ParseInnerText(this.definition.Name, true);
29 |
30 | ///
31 | /// ID of this social group.
32 | ///
33 | public string? Id => ParseHrefId(this.definition.Name);
34 |
35 | ///
36 | /// Link to this social group's page.
37 | ///
38 | public Uri? Link => ParseHref(this.definition.Name);
39 |
40 | ///
41 | /// of this social group's icon.
42 | ///
43 | public IconLayers IconLayers => new(this.RootNode, this.definition.IconLayers);
44 |
45 | ///
46 | /// String representation of the gear slot.
47 | ///
48 | /// The name of the item.
49 | public override string ToString() => this.Name;
50 | }
--------------------------------------------------------------------------------
/NetStone/NetStone.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.1
5 |
6 | NetStone
7 | 1.4.1
8 | 1.4.1
9 | Portable and modern Lodestone library.
10 | goaaats, Koenari
11 | https://github.com/xivapi/NetStone
12 | https://github.com/xivapi/NetStone
13 |
14 | LICENSE
15 | README.md
16 |
17 | true
18 | true
19 |
20 | 10.0
21 | enable
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 | true
32 | true
33 | NetStone.xml
34 | snupkg
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/NetStone/Search/Character/CharacterSearchQuery.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Text;
3 | using NetStone.StaticData;
4 |
5 | namespace NetStone.Search.Character;
6 |
7 | ///
8 | /// Models a search for characters
9 | ///
10 | public class CharacterSearchQuery : ISearchQuery
11 | {
12 | ///
13 | /// Name to search
14 | ///
15 | public string CharacterName { get; set; } = "";
16 |
17 | ///
18 | /// Homeworld for search
19 | ///
20 | public string World { get; set; } = "";
21 |
22 | ///
23 | /// Datacenter to search
24 | ///
25 | public string DataCenter { get; set; } = "";
26 |
27 | ///
28 | /// Role to search for
29 | ///
30 | public Role Role { get; set; }
31 |
32 | ///
33 | /// Job to search for
34 | ///
35 | public ClassJob ClassJob { get; set; }
36 |
37 | ///
38 | /// Race to search for
39 | ///
40 | public Race Race { get; set; }
41 |
42 | ///
43 | /// Tribe/Clan to search for
44 | ///
45 | public Tribe Tribe { get; set; }
46 |
47 | ///
48 | /// Grand Company affiliation to search for
49 | ///
50 | public GrandCompany GrandCompany { get; set; } = GrandCompany.None;
51 |
52 | ///
53 | /// Languages to include
54 | ///
55 | public Language Language { get; set; } =
56 | Language.Japanese | Language.English | Language.German | Language.French;
57 |
58 | ///
59 | /// Sort order
60 | ///
61 | public SortKind SortKind { get; set; } = SortKind.NameAtoZ;
62 |
63 | ///
64 | /// Construct search string to append to uri.
65 | /// Throws if incompatible query parameters are used
66 | ///
67 | /// Query string
68 | ///
69 | public string BuildQueryString()
70 | {
71 | if (string.IsNullOrEmpty(this.CharacterName))
72 | throw new ArgumentException("CharacterName must not be empty or null.", nameof(this.CharacterName));
73 |
74 | if (!string.IsNullOrEmpty(this.World) && !string.IsNullOrEmpty(this.DataCenter))
75 | throw new ArgumentException(
76 | "You cannot specify World and DataCenter at the same time in one search query.");
77 |
78 | if (this.Role != Role.None && this.ClassJob != ClassJob.None)
79 | throw new ArgumentException(
80 | "You cannot specify Role and ClassJob at the same time in one search query.");
81 |
82 | if (this.Race != Race.None && this.Tribe != Tribe.None)
83 | throw new ArgumentException(
84 | "You cannot specify Race and Tribe at the same time in one search query.");
85 |
86 | var query = new StringBuilder();
87 |
88 | query.Append($"?q={this.CharacterName}");
89 |
90 |
91 | if (!string.IsNullOrEmpty(this.World))
92 | query.Append($"&worldname={this.World}");
93 |
94 | if (!string.IsNullOrEmpty(this.DataCenter))
95 | query.Append($"&worldname=_dc_{this.DataCenter}");
96 |
97 |
98 | if (this.Role != Role.None)
99 | query.Append($"&classjob=_job_{this.Role.ToString().ToUpperInvariant()}");
100 |
101 | if (this.ClassJob != ClassJob.None)
102 | query.Append($"&classjob={(int)this.ClassJob}");
103 |
104 |
105 | if (this.Tribe != Tribe.None)
106 | query.Append($"&race_tribe=tribe_{(int)this.Tribe}");
107 |
108 | if (this.Race != Race.None)
109 | query.Append($"&race_tribe=race_{(int)this.Race}");
110 |
111 |
112 | if (this.GrandCompany.HasFlag(GrandCompany.NoAffiliation))
113 | query.Append("&gcid=0");
114 |
115 | if (this.GrandCompany.HasFlag(GrandCompany.Maelstrom))
116 | query.Append("&gcid=1");
117 |
118 | if (this.GrandCompany.HasFlag(GrandCompany.OrderOfTheTwinAdder))
119 | query.Append("&gcid=2");
120 |
121 | if (this.GrandCompany.HasFlag(GrandCompany.ImmortalFlames))
122 | query.Append("&gcid=3");
123 |
124 |
125 | if (this.Language.HasFlag(Language.Japanese))
126 | query.Append("&blog_lang=ja");
127 |
128 | if (this.Language.HasFlag(Language.English))
129 | query.Append("&blog_lang=en");
130 |
131 | if (this.Language.HasFlag(Language.German))
132 | query.Append("&blog_lang=de");
133 |
134 | if (this.Language.HasFlag(Language.French))
135 | query.Append("&blog_lang=fr");
136 |
137 |
138 | query.Append($"&order={(int)this.SortKind}");
139 |
140 | return query.ToString();
141 | }
142 | }
--------------------------------------------------------------------------------
/NetStone/Search/Character/SortKind.cs:
--------------------------------------------------------------------------------
1 | namespace NetStone.Search.Character;
2 |
3 | ///
4 | /// Result sorting schemes for character searches.
5 | ///
6 | public enum SortKind
7 | {
8 | ///
9 | /// Sort by name A to Z
10 | ///
11 | NameAtoZ = 1,
12 |
13 | ///
14 | /// Sort by name Z to A
15 | ///
16 | NameZtoA = 2,
17 |
18 | ///
19 | /// Sort by Homeworld A to Z
20 | ///
21 | WorldAtoZ = 3,
22 |
23 | ///
24 | /// Sort by Homeworld Z to A
25 | ///
26 | WorldZtoA = 4,
27 |
28 | ///
29 | /// Sort by level descending
30 | ///
31 | LevelDesc = 5,
32 |
33 | ///
34 | /// Sort by level ascending
35 | ///
36 | LevelAsc = 6,
37 | }
--------------------------------------------------------------------------------
/NetStone/Search/FreeCompany/ActiveMembers.cs:
--------------------------------------------------------------------------------
1 | namespace NetStone.Search.FreeCompany;
2 |
3 | ///
4 | /// Active member filters for FC searches.
5 | ///
6 | public enum ActiveMembers
7 | {
8 | ///
9 | /// Include all FCs
10 | ///
11 | All,
12 |
13 | ///
14 | /// Filter for FCs with less than 10 members
15 | ///
16 | OneToTen,
17 |
18 | ///
19 | /// Filter for FCs with 11-30 members
20 | ///
21 | ElevenToThirty,
22 |
23 | ///
24 | /// Filter for FCs with 31-50 members
25 | ///
26 | ThirtyOneToFifty,
27 |
28 | ///
29 | /// Filter for FCs with more then 50 members
30 | ///
31 | OverFiftyOne,
32 | }
--------------------------------------------------------------------------------
/NetStone/Search/FreeCompany/ActiveTimes.cs:
--------------------------------------------------------------------------------
1 | namespace NetStone.Search.FreeCompany;
2 |
3 | ///
4 | /// Active time filters for FC searches.
5 | ///
6 | public enum ActiveTimes
7 | {
8 | ///
9 | /// All options specified
10 | ///
11 | All,
12 |
13 | ///
14 | /// FC is active on week days
15 | ///
16 | WeekdaysOnly,
17 |
18 | ///
19 | /// FC is active on weekends
20 | ///
21 | WeekendsOnly,
22 |
23 | ///
24 | /// FC is always active
25 | ///
26 | Always,
27 | }
--------------------------------------------------------------------------------
/NetStone/Search/FreeCompany/Focus.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace NetStone.Search.FreeCompany;
4 |
5 | ///
6 | /// Focus filters for FC searches.
7 | ///
8 | [Flags]
9 | public enum Focus
10 | {
11 | ///
12 | /// No focus specified
13 | ///
14 | NotSpecified = 0,
15 |
16 | ///
17 | /// Focus on Role Play
18 | ///
19 | RolePlaying = 1 << 0,
20 |
21 | ///
22 | /// Focus on leveling
23 | ///
24 | Leveling = 1 << 1,
25 |
26 | ///
27 | /// Focus on casual content
28 | ///
29 | Casual = 1 << 2,
30 |
31 | ///
32 | /// Focus on hardcore content
33 | ///
34 | Hardcore = 1 << 3,
35 |
36 | ///
37 | /// Focus on Dungeon content
38 | ///
39 | Dungeons = 1 << 4,
40 |
41 | ///
42 | /// Focus on guild heists
43 | ///
44 | Guildhests = 1 << 5,
45 |
46 | ///
47 | /// Focus on trials
48 | ///
49 | Trials = 1 << 6,
50 |
51 | ///
52 | /// Focus on raiding
53 | ///
54 | Raids = 1 << 7,
55 |
56 | ///
57 | /// Focus on PvP
58 | ///
59 | PvP = 1 << 8,
60 | }
--------------------------------------------------------------------------------
/NetStone/Search/FreeCompany/FreeCompanySearchQuery.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Text;
3 | using NetStone.StaticData;
4 |
5 | namespace NetStone.Search.FreeCompany;
6 |
7 | ///
8 | /// Models a search query for Free companies
9 | ///
10 | public class FreeCompanySearchQuery : ISearchQuery
11 | {
12 | ///
13 | /// Name to search for
14 | ///
15 | public string Name { get; set; } = "";
16 |
17 | ///
18 | /// World name the FC should belong to
19 | ///
20 | public string World { get; set; } = "";
21 |
22 | ///
23 | /// Data center the FC should belong to
24 | ///
25 | public string DataCenter { get; set; } = "";
26 |
27 | ///
28 | /// IF the FC is recruiting via Community Finder
29 | ///
30 | public bool IsCommunityFinderRecruiting { get; set; }
31 |
32 | ///
33 | /// Filter by active times
34 | ///
35 | public ActiveTimes ActiveTimes { get; set; } = ActiveTimes.All;
36 |
37 | ///
38 | /// Filter by number of active players
39 | ///
40 | public ActiveMembers ActiveMembers { get; set; } = ActiveMembers.All;
41 |
42 | ///
43 | /// Filter by recruitment status
44 | ///
45 | public Recruitment Recruitment { get; set; } = Recruitment.All;
46 |
47 | ///
48 | /// Filter by housing status
49 | ///
50 | public Housing Housing { get; set; } = Housing.All;
51 |
52 | ///
53 | /// Filter by content focus of the FC
54 | ///
55 | public Focus Focus { get; set; }
56 |
57 | ///
58 | /// Filter by type of players the FC is seeking
59 | ///
60 | public Seeking Seeking { get; set; }
61 |
62 | ///
63 | /// Filter for Grand Company membership
64 | ///
65 | public GrandCompany GrandCompany { get; set; } = GrandCompany.None;
66 |
67 | ///
68 | /// How to sort results
69 | ///
70 | public SortKind SortKind { get; set; } = SortKind.NameAtoZ;
71 |
72 | ///
73 | ///
74 | public string BuildQueryString()
75 | {
76 | if (!string.IsNullOrEmpty(this.World) && !string.IsNullOrEmpty(this.DataCenter))
77 | throw new ArgumentException(
78 | "You cannot specify World and DataCenter at the same time in one search query.");
79 |
80 | var query = new StringBuilder($"?q={this.Name}");
81 |
82 | if (this.IsCommunityFinderRecruiting)
83 | query.Append("&cf_public=1");
84 |
85 |
86 | if (!string.IsNullOrEmpty(this.World))
87 | query.Append($"&worldname={this.World}");
88 |
89 | if (!string.IsNullOrEmpty(this.DataCenter))
90 | query.Append($"&worldname=_dc_{this.DataCenter}");
91 |
92 |
93 | if (this.ActiveTimes != ActiveTimes.All)
94 | query.Append($"&activetime={(int)this.ActiveTimes}");
95 |
96 |
97 | if (this.Recruitment != Recruitment.All)
98 | query.Append($"&join={(int)this.Recruitment}");
99 |
100 |
101 | if (this.Housing != Housing.All)
102 | query.Append($"&house={(int)this.Housing}");
103 |
104 |
105 | if (this.ActiveMembers == ActiveMembers.OneToTen)
106 | query.Append("&character_count=1-10");
107 |
108 | if (this.ActiveMembers == ActiveMembers.ElevenToThirty)
109 | query.Append("&character_count=11-30");
110 |
111 | if (this.ActiveMembers == ActiveMembers.ThirtyOneToFifty)
112 | query.Append("&character_count=31-50");
113 |
114 | if (this.ActiveMembers == ActiveMembers.OverFiftyOne)
115 | query.Append("&character_count=50-");
116 |
117 |
118 | if (this.Focus.HasFlag(Focus.RolePlaying))
119 | query.Append("&activities=0");
120 |
121 | if (this.Focus.HasFlag(Focus.Leveling))
122 | query.Append("&activities=1");
123 |
124 | if (this.Focus.HasFlag(Focus.Casual))
125 | query.Append("&activities=2");
126 |
127 | if (this.Focus.HasFlag(Focus.Hardcore))
128 | query.Append("&activities=3");
129 |
130 | if (this.Focus.HasFlag(Focus.Dungeons))
131 | query.Append("&activities=6");
132 |
133 | if (this.Focus.HasFlag(Focus.Guildhests))
134 | query.Append("&activities=4");
135 |
136 | if (this.Focus.HasFlag(Focus.Trials))
137 | query.Append("&activities=5");
138 |
139 | if (this.Focus.HasFlag(Focus.Raids))
140 | query.Append("&activities=7");
141 |
142 | if (this.Focus.HasFlag(Focus.PvP))
143 | query.Append("&activities=8");
144 |
145 |
146 | if (this.Seeking.HasFlag(Seeking.Tank))
147 | query.Append("&roles=16");
148 |
149 | if (this.Seeking.HasFlag(Seeking.Healer))
150 | query.Append("&roles=17");
151 |
152 | if (this.Seeking.HasFlag(Seeking.Dps))
153 | query.Append("&roles=18");
154 |
155 | if (this.Seeking.HasFlag(Seeking.Crafter))
156 | query.Append("&roles=19");
157 |
158 | if (this.Seeking.HasFlag(Seeking.Gatherer))
159 | query.Append("&roles=20");
160 |
161 |
162 | if (this.GrandCompany.HasFlag(GrandCompany.Maelstrom))
163 | query.Append("&gcid=1");
164 |
165 | if (this.GrandCompany.HasFlag(GrandCompany.OrderOfTheTwinAdder))
166 | query.Append("&gcid=2");
167 |
168 | if (this.GrandCompany.HasFlag(GrandCompany.ImmortalFlames))
169 | query.Append("&gcid=3");
170 |
171 |
172 | query.Append($"&order={(int)this.SortKind}");
173 |
174 | return query.ToString();
175 | }
176 | }
--------------------------------------------------------------------------------
/NetStone/Search/FreeCompany/Housing.cs:
--------------------------------------------------------------------------------
1 | namespace NetStone.Search.FreeCompany;
2 |
3 | ///
4 | /// Housing filters for FC searches.
5 | ///
6 | public enum Housing
7 | {
8 | ///
9 | /// Do not filter by housing
10 | ///
11 | All = 99,
12 |
13 | ///
14 | /// Filter for FCs with an estate built
15 | ///
16 | EstateBuilt = 2,
17 |
18 | ///
19 | /// Filter for FCs with a plot but no estate built
20 | ///
21 | PlotOnly = 1,
22 |
23 | ///
24 | /// Filter for Fcs with neither an estate nor a plot
25 | ///
26 | NoEstateOrPlot = 0,
27 | }
--------------------------------------------------------------------------------
/NetStone/Search/FreeCompany/Recruitment.cs:
--------------------------------------------------------------------------------
1 | namespace NetStone.Search.FreeCompany;
2 |
3 | ///
4 | /// Recruitment filters for FC searches.
5 | ///
6 | public enum Recruitment
7 | {
8 | ///
9 | /// Dot not filter by recruitment status
10 | ///
11 | All = 99,
12 |
13 | ///
14 | /// Filter for groups actively recruiting
15 | ///
16 | Open = 1,
17 |
18 | ///
19 | /// Filter for groups not actively recruiting
20 | ///
21 | Closed = 0
22 | }
--------------------------------------------------------------------------------
/NetStone/Search/FreeCompany/Seeking.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace NetStone.Search.FreeCompany;
4 |
5 | ///
6 | /// Seeking player filters for FC searches.
7 | ///
8 | [Flags]
9 | public enum Seeking
10 | {
11 | ///
12 | /// No status specified
13 | ///
14 | NotSpecified = 0,
15 |
16 | ///
17 | /// Seeking tanks
18 | ///
19 | Tank = 1 << 0,
20 |
21 | ///
22 | /// Seeking healers
23 | ///
24 | Healer = 1 << 1,
25 |
26 | ///
27 | /// Seeking DPS
28 | ///
29 | Dps = 1 << 2,
30 |
31 | ///
32 | /// Seeking crafters
33 | ///
34 | Crafter = 1 << 3,
35 |
36 | ///
37 | /// Seeking gatherers
38 | ///
39 | Gatherer = 1 << 4,
40 | }
--------------------------------------------------------------------------------
/NetStone/Search/FreeCompany/SortKind.cs:
--------------------------------------------------------------------------------
1 | namespace NetStone.Search.FreeCompany;
2 |
3 | ///
4 | /// Result sorting schemes for FC searches.
5 | ///
6 | public enum SortKind
7 | {
8 | ///
9 | /// Sort by name from A to Z
10 | ///
11 | NameAtoZ = 1,
12 |
13 | ///
14 | /// Sort by name from Z to A
15 | ///
16 | NameZtoA = 2,
17 |
18 | ///
19 | /// Sort by member count (high to low)
20 | ///
21 | MembershipHighToLow = 3,
22 |
23 | ///
24 | /// Sort by member count (low to high)
25 | ///
26 | MembershipLowToHigh = 4,
27 |
28 | ///
29 | /// Sort by foundation date (newest first)
30 | ///
31 | DateFoundedMostRecent = 5,
32 |
33 | ///
34 | /// Sort by foundation date (oldest first)
35 | ///
36 | DateFoundedOldest = 6,
37 | }
--------------------------------------------------------------------------------
/NetStone/Search/ISearchQuery.cs:
--------------------------------------------------------------------------------
1 | namespace NetStone.Search;
2 |
3 | ///
4 | /// Models a search query for search requests
5 | ///
6 | public interface ISearchQuery
7 | {
8 | ///
9 | /// Constructs the query to send modeling this search query
10 | ///
11 | /// Search parameters to append to the request uri
12 | public string BuildQueryString();
13 | }
--------------------------------------------------------------------------------
/NetStone/Search/Linkshell/LinkshellSearchQuery.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Text;
3 |
4 | namespace NetStone.Search.Linkshell;
5 |
6 | ///
7 | /// Models a search for a link shell
8 | ///
9 | public class LinkshellSearchQuery : BaseLinkshellSearchQuery
10 | {
11 |
12 | ///
13 | /// Datacenter
14 | /// This is ignored if is set
15 | ///
16 | public string DataCenter { get; set; } = "";
17 |
18 | ///
19 | /// Home-world
20 | ///
21 | public string HomeWorld { get; set; } = "";
22 | ///
23 | public override string BuildQueryString()
24 | {
25 | if(string.IsNullOrEmpty(this.Name))
26 | throw new ArgumentException("Name must not be empty or null.", nameof(this.Name));
27 |
28 | var query = new StringBuilder();
29 |
30 | query.Append($"?q={this.Name}");
31 | if(this.RecruitingOnly)
32 | query.Append("&cf_public=1");
33 | query.Append($"&worldname={(string.IsNullOrEmpty(this.HomeWorld) ? $"_dc_{this.DataCenter}" : this.HomeWorld)}");
34 | query.Append($@"&character_count={this.ActiveMembers switch
35 | {
36 | LinkshellSizeCategory.OneToTen => "1-10",
37 | LinkshellSizeCategory.ElevenToThirty => "11-30",
38 | LinkshellSizeCategory.ThirtyOneToFifty => "31-51",
39 | LinkshellSizeCategory.OverFiftyOne => "51-",
40 | _ => "",
41 | }}");
42 | query.Append($"&order={this.Sorting:D}");
43 |
44 | return query.ToString();
45 | }
46 | }
47 |
48 | ///
49 | /// Models a search for a cross world link shell
50 | ///
51 | public class CrossworldLinkshellSearchQuery : BaseLinkshellSearchQuery
52 | {
53 |
54 | ///
55 | /// Datacenter
56 | ///
57 | public string DataCenter { get; set; } = "";
58 | ///
59 | public override string BuildQueryString()
60 | {
61 | if(string.IsNullOrEmpty(this.Name))
62 | throw new ArgumentException("Name must not be empty or null.", nameof(this.Name));
63 |
64 | var query = new StringBuilder();
65 |
66 | query.Append($"?q={this.Name}");
67 | if(this.RecruitingOnly)
68 | query.Append("&cf_public=1");
69 | query.Append($"&dcname={this.DataCenter}");
70 | query.Append($@"&character_count={this.ActiveMembers switch
71 | {
72 | LinkshellSizeCategory.OneToTen => "1-10",
73 | LinkshellSizeCategory.ElevenToThirty => "11-30",
74 | LinkshellSizeCategory.ThirtyOneToFifty => "31-51",
75 | LinkshellSizeCategory.OverFiftyOne => "51-",
76 | _ => "",
77 | }}");
78 | query.Append($"&order={this.Sorting:D}");
79 |
80 | return query.ToString();
81 | }
82 | }
83 |
84 | ///
85 | /// Models a search for a cross world link shell
86 | ///
87 | public abstract class BaseLinkshellSearchQuery : ISearchQuery
88 | {
89 | ///
90 | /// Only search for actively recruiting
91 | ///
92 | public bool RecruitingOnly { get; set; }
93 |
94 | ///
95 | /// Name
96 | ///
97 | public string Name { get; set; } = "";
98 |
99 | ///
100 | /// Active member count
101 | ///
102 | public LinkshellSizeCategory ActiveMembers { get; set; } = LinkshellSizeCategory.All;
103 |
104 |
105 | ///
106 | /// Sort order
107 | ///
108 | public LinkshellSortKind Sorting { get; set; } = LinkshellSortKind.CreationDateNewToOld;
109 |
110 | ///
111 | public abstract string BuildQueryString();
112 | }
113 |
114 | ///
115 | /// Available choice for member count
116 | ///
117 | public enum LinkshellSizeCategory
118 | {
119 | ///
120 | /// All
121 | ///
122 | All,
123 | ///
124 | /// 1-10
125 | ///
126 | OneToTen,
127 | ///
128 | /// 11-30
129 | ///
130 | ElevenToThirty,
131 | ///
132 | /// 31-50
133 | ///
134 | ThirtyOneToFifty,
135 | ///
136 | /// Over 51
137 | ///
138 | OverFiftyOne,
139 | }
140 |
141 | ///
142 | /// Ways to sort linkshell and cwls search results
143 | ///
144 | public enum LinkshellSortKind
145 | {
146 | ///
147 | /// Creation date (newest to oldest)
148 | ///
149 | CreationDateNewToOld = 1,
150 | ///
151 | /// Creation date (oldest to newest)
152 | ///
153 | CreationDateOldToNew = 2,
154 | ///
155 | /// Name (A - Z)
156 | ///
157 | NameAtoZ = 3,
158 | ///
159 | /// Name (Z - A)
160 | ///
161 | NameZtoA = 4,
162 | ///
163 | /// Membership (high to low)
164 | ///
165 | MemberCountDesc = 5,
166 | ///
167 | /// Membership (low to high)
168 | ///
169 | MemberCountAsc = 6,
170 |
171 |
172 | }
--------------------------------------------------------------------------------
/NetStone/StaticData/ClassJob.cs:
--------------------------------------------------------------------------------
1 | namespace NetStone.StaticData;
2 |
3 | ///
4 | /// The ClassJob IDs.
5 | ///
6 | public enum ClassJob
7 | {
8 | ///
9 | /// No job specified
10 | ///
11 | None,
12 |
13 | ///
14 | /// Gladiator class
15 | ///
16 | Gladiator = 1,
17 |
18 | ///
19 | /// Pugilist class
20 | ///
21 | Pugilist = 2,
22 |
23 | ///
24 | /// Marauder class
25 | ///
26 | Marauder = 3,
27 |
28 | ///
29 | /// Lancer class
30 | ///
31 | Lancer = 4,
32 |
33 | ///
34 | /// Archer class
35 | ///
36 | Archer = 5,
37 |
38 | ///
39 | /// Conjurer class
40 | ///
41 | Conjurer = 6,
42 |
43 | ///
44 | /// Thaumaturge class
45 | ///
46 | Thaumaturge = 7,
47 |
48 | ///
49 | /// Carpenter
50 | ///
51 | Carpenter = 8,
52 |
53 | ///
54 | /// Blacksmith
55 | ///
56 | Blacksmith = 9,
57 |
58 | ///
59 | /// Armorer
60 | ///
61 | Armorer = 10,
62 |
63 | ///
64 | /// Goldsmith
65 | ///
66 | Goldsmith = 11,
67 |
68 | ///
69 | /// Leatherworker
70 | ///
71 | Leatherworker = 12,
72 |
73 | ///
74 | /// Weaver
75 | ///
76 | Weaver = 13,
77 |
78 | ///
79 | /// Alchemist
80 | ///
81 | Alchemist = 14,
82 |
83 | ///
84 | /// Culinarian
85 | ///
86 | Culinarian = 15,
87 |
88 | ///
89 | /// Miner
90 | ///
91 | Miner = 16,
92 |
93 | ///
94 | /// Botanist
95 | ///
96 | Botanist = 17,
97 |
98 | ///
99 | /// Fisher
100 | ///
101 | Fisher = 18,
102 |
103 | ///
104 | /// Paladin
105 | ///
106 | Paladin = 19,
107 |
108 | ///
109 | /// Monk
110 | ///
111 | Monk = 20,
112 |
113 | ///
114 | /// Warrior
115 | ///
116 | Warrior = 21,
117 |
118 | ///
119 | /// Dragoon
120 | ///
121 | Dragoon = 22,
122 |
123 | ///
124 | /// Bard
125 | ///
126 | Bard = 23,
127 |
128 | ///
129 | /// White Mage
130 | ///
131 | WhiteMage = 24,
132 |
133 | ///
134 | /// Black Mage
135 | ///
136 | BlackMage = 25,
137 |
138 | ///
139 | /// Arcanist class
140 | ///
141 | Arcanist = 26,
142 |
143 | ///
144 | /// Summoner
145 | ///
146 | Summoner = 27,
147 |
148 | ///
149 | /// Scholar
150 | ///
151 | Scholar = 28,
152 |
153 | ///
154 | /// Rogue class
155 | ///
156 | Rogue = 29,
157 |
158 | ///
159 | /// Ninja
160 | ///
161 | Ninja = 30,
162 |
163 | ///
164 | /// Machinist
165 | ///
166 | Machinist = 31,
167 |
168 | ///
169 | /// Dark Knight
170 | ///
171 | DarkKnight = 32,
172 |
173 | ///
174 | /// Astrologian
175 | ///
176 | Astrologian = 33,
177 |
178 | ///
179 | /// Samurai
180 | ///
181 | Samurai = 34,
182 |
183 | ///
184 | /// Red Mage
185 | ///
186 | RedMage = 35,
187 |
188 | ///
189 | /// Blue Mage
190 | ///
191 | BlueMage = 36,
192 |
193 | ///
194 | /// Gunbreaker
195 | ///
196 | Gunbreaker = 37,
197 |
198 | ///
199 | /// Dancer
200 | ///
201 | Dancer = 38,
202 |
203 | ///
204 | /// Reaper
205 | ///
206 | Reaper = 39,
207 |
208 | ///
209 | /// Sage
210 | ///
211 | Sage = 40,
212 |
213 | ///
214 | /// Viper
215 | ///
216 | Viper = 41,
217 |
218 | ///
219 | /// Pictomancer
220 | ///
221 | Pictomancer = 42
222 | }
--------------------------------------------------------------------------------
/NetStone/StaticData/GrandCompany.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace NetStone.StaticData;
4 |
5 | ///
6 | /// The Grand Company IDs.
7 | ///
8 | [Flags]
9 | public enum GrandCompany
10 | {
11 | ///
12 | /// Unspecified
13 | ///
14 | None = 0,
15 |
16 | ///
17 | /// No affiliation with any grand company
18 | ///
19 | NoAffiliation = 1 << 0,
20 |
21 | ///
22 | /// Affiliated with Maelstrom
23 | ///
24 | Maelstrom = 1 << 1,
25 |
26 | ///
27 | /// Affiliated with The Twin Adder
28 | ///
29 | OrderOfTheTwinAdder = 1 << 2,
30 |
31 | ///
32 | /// Affiliated with the Immortal Flames
33 | ///
34 | ImmortalFlames = 1 << 3,
35 | }
--------------------------------------------------------------------------------
/NetStone/StaticData/Language.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace NetStone.StaticData;
4 |
5 | ///
6 | /// The supported Lodestone languages.
7 | ///
8 | [Flags]
9 | public enum Language
10 | {
11 | ///
12 | /// No language specified
13 | ///
14 | None = 0,
15 |
16 | ///
17 | /// Japanese
18 | ///
19 | Japanese = 1 << 0,
20 |
21 | ///
22 | /// English
23 | ///
24 | English = 1 << 1,
25 |
26 | ///
27 | /// German
28 | ///
29 | German = 1 << 2,
30 |
31 | ///
32 | /// French
33 | ///
34 | French = 1 << 3,
35 | }
--------------------------------------------------------------------------------
/NetStone/StaticData/Race.cs:
--------------------------------------------------------------------------------
1 | namespace NetStone.StaticData;
2 |
3 | ///
4 | /// The possible game character races.
5 | ///
6 | public enum Race
7 | {
8 | ///
9 | /// No Race
10 | ///
11 | None,
12 |
13 | ///
14 | /// Hyur Race
15 | ///
16 | Hyur,
17 |
18 | ///
19 | /// Elezen Race
20 | ///
21 | Elezen,
22 |
23 | ///
24 | /// Lalafell race
25 | ///
26 | Lalafell,
27 |
28 | ///
29 | /// Miqo'te race
30 | ///
31 | Miqote,
32 |
33 | ///
34 | /// Roegadyn race
35 | ///
36 | Roegadyn,
37 |
38 | ///
39 | /// Au Ra race
40 | ///
41 | AuRa,
42 |
43 | ///
44 | /// Rothgar race
45 | ///
46 | Hrothgar,
47 |
48 | ///
49 | /// Viera race
50 | ///
51 | Viera,
52 | }
--------------------------------------------------------------------------------
/NetStone/StaticData/Role.cs:
--------------------------------------------------------------------------------
1 | namespace NetStone.StaticData;
2 |
3 | ///
4 | /// The game combat roles.
5 | ///
6 | public enum Role
7 | {
8 | ///
9 | /// No role
10 | ///
11 | None,
12 |
13 | ///
14 | /// Tank role
15 | ///
16 | Tank,
17 |
18 | ///
19 | /// Healer role
20 | ///
21 | Healer,
22 |
23 | ///
24 | /// DPS role
25 | ///
26 | Dps,
27 | }
--------------------------------------------------------------------------------
/NetStone/StaticData/Tribe.cs:
--------------------------------------------------------------------------------
1 | namespace NetStone.StaticData;
2 |
3 | ///
4 | /// The possible game character tribes.
5 | ///
6 | public enum Tribe
7 | {
8 | ///
9 | /// No tribe
10 | ///
11 | None,
12 |
13 | ///
14 | /// Midlander Hyur
15 | ///
16 | Midlander,
17 |
18 | ///
19 | /// Highlander Hyur
20 | ///
21 | Highlander,
22 |
23 | ///
24 | /// Wildwood Elezen
25 | ///
26 | Wildwood,
27 |
28 | ///
29 | /// Duskwight Elezen
30 | ///
31 | Duskwight,
32 |
33 | ///
34 | /// Plainsfolk Lalafell
35 | ///
36 | Plainsfolk,
37 |
38 | ///
39 | /// Dunesfolk Lalafell
40 | ///
41 | Dunesfolk,
42 |
43 | ///
44 | /// Seeker of the Sun Miqo'te
45 | ///
46 | SeekeroftheSun,
47 |
48 | ///
49 | /// Keeper of the Moon Miqo'te
50 | ///
51 | KeeperoftheMoon,
52 |
53 | ///
54 | /// Seawolf Roegadyn
55 | ///
56 | SeaWolf,
57 |
58 | ///
59 | /// Hellsguard Roegadyn
60 | ///
61 | Hellsguard,
62 |
63 | ///
64 | /// Raen Au Ra
65 | ///
66 | Raen,
67 |
68 | ///
69 | /// Xaela Au Ra
70 | ///
71 | Xaela,
72 |
73 | ///
74 | /// Helion Hrothgar
75 | ///
76 | Helions,
77 |
78 | ///
79 | /// Hrothgar of The Lost
80 | ///
81 | TheLost,
82 |
83 | ///
84 | /// Rava Viera
85 | ///
86 | Rava,
87 |
88 | ///
89 | /// Veena Viera
90 | ///
91 | Veena,
92 | }
--------------------------------------------------------------------------------
/NetStone/UserAgent.cs:
--------------------------------------------------------------------------------
1 | namespace NetStone;
2 |
3 | internal enum UserAgent
4 | {
5 | Desktop,
6 | Mobile,
7 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # NetStone [](https://www.nuget.org/packages/NetStone) 
2 |
3 |
4 | NetStone is a portable and modern .NET FFXIV Lodestone API.
5 |
6 | ## What works
7 |
8 | - [x] Characters
9 | - [x] Character Search
10 | - [x] FCs
11 | - [x] FC Search
12 | - [ ] PvP Teams
13 | - [ ] PvP Team Search
14 | - [x] Linkshell
15 | - [x] Linkshell Search
16 | - [x] CWLS
17 | - [x] CWLS Search
18 |
19 | Eorzea DB support is not planned.
20 |
21 | ## Usage
22 |
23 | ### Set up the client
24 | If you want to use NetStone you need to create one instance of the LodestoneClient and use this instance for all your requests.
25 | Note that this operation downloads current definitions and can therefore take an unknown amount of time or even throw and exception.
26 |
27 | #### Example Code
28 |
29 | ```C#
30 | try{
31 | var lodestoneClient = await LodestoneClient.GetClientAsync();
32 | } catch(HttpRequestException ex){
33 | ...
34 | }
35 | ```
36 |
37 | ### Retrieve character information
38 | Character information is fetched using the character's lodestone ID (the number contained in the Url).
39 | If the ID is not known to you, you can use the built in search functionality to look up a character by name and home world.
40 | If you need to fetch data for a specific character often it is best practice to save the Lodestone Id.
41 | Note that the search can have 0 results and that a character is null if the request failed.
42 | #### Example code
43 | ```C#
44 | try
45 | {
46 | //Get Lodestone Id if not known
47 | var searchResponse = await lodestoneClient.SearchCharacter(new CharacterSearchQuery()
48 | {
49 | CharacterName = "Name Surname",
50 | World = "Lich"
51 | });
52 | var lodestoneCharacter =
53 | searchResponse?.Results
54 | .FirstOrDefault(entry => entry.Name == "Name Surname");
55 | string lodestoneId = lodestoneCharacter.Id;
56 |
57 | //If Lodestone id is known
58 | var lodestoneCharacter = await lodestoneClient.GetCharacter(lodestoneId);
59 | } catch(HttpRequestException e) {
60 | //Handle potential errors in web request
61 | ...
62 | }
63 | ```
--------------------------------------------------------------------------------
/compile-fbs.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | echo Clearing ./NetStone/GameData/Internal/...
4 | rm -rf ./NetStone/GameData/Internal/
5 |
6 | echo Packing data exports...
7 | ./flatc --csharp -o ./NetStone.GameData.Packs/Internal/ --gen-onefile --filename-suffix "" ./lib/lodestone-data-exports/schema/*.fbs
8 | #go-bindata -o internal/pack/exports/gamedata.go -prefix "lodestone-data-exports/pack" -ignore="(LICENSE|README.md|.git|.gitignore|meta.json|LodestoneDataExporter.*|schema|.vscode)" lodestone-data-exports/...
9 | #sed -i "s/package main/package exports/g" internal/pack/exports/gamedata.go
10 |
11 | find -D exec ./NetStone.GameData.Packs/Internal/ -type f -exec sed -i 's/using global::Google.FlatBuffers;/using global::FlatBuffers;/g' {} \;
12 | #find -D exec ./NetStone.GameData.Packs/Internal/ -type f -exec sed -i 's/FFXIV/NetStone.GameData.Internal/g' {} \;
13 |
14 | echo Done!
15 |
--------------------------------------------------------------------------------
/patch-flatbuffers.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | sed -i 's/netstandard2.0;net46/netstandard2.0/g' ./lib/flatbuffers/net/FlatBuffers/FlatBuffers.csproj
4 |
5 | echo Done!
6 |
--------------------------------------------------------------------------------