Skip to content

Commit

Permalink
Merge pull request #11 from planetarium/PDX-382
Browse files Browse the repository at this point in the history
PDX-382: Make ArenaRanking.Avatar optional on query
  • Loading branch information
XxshiftxX authored Mar 5, 2024
2 parents e6604b4 + e8c8c1b commit 6d7a303
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 115 deletions.
12 changes: 7 additions & 5 deletions NineChroniclesUtilBackend/Models/Arena/ArenaRanking.cs
Original file line number Diff line number Diff line change
@@ -1,30 +1,32 @@
using System.Text.Json.Serialization;
using NineChroniclesUtilBackend.Models.Agent;

namespace NineChroniclesUtilBackend.Models.Arena;

public class ArenaRanking(
string AvatarAddress,
string ArenaAddress,
int Cp,
int Win,
int Lose,
long Rank,
int Ticket,
int TicketResetCount,
int PurchasedTicketCount,
int Score,
Avatar Avatar
int Score
)
{
public string AvatarAddress { get; set; } = AvatarAddress;
public string ArenaAddress { get; set; } = ArenaAddress;
public int Cp { get; set; } = Cp;
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public int? CP { get; set; }
public int Win { get; set; } = Win;
public int Lose { get; set; } = Lose;
public long Rank { get; set; } = Rank;
public int Ticket { get; set; } = Ticket;
public int TicketResetCount { get; set; } = TicketResetCount;
public int PurchasedTicketCount { get; set; } = PurchasedTicketCount;
public int Score { get; set; } = Score;
public Avatar Avatar { get; set; } = Avatar;

[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public Avatar? Avatar { get; set; }
}
129 changes: 47 additions & 82 deletions NineChroniclesUtilBackend/Repositories/ArenaRankingRespository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,93 +39,58 @@ public async Task<long> GetRankByAvatarAddress(string avatarAddress)

public async Task<List<ArenaRanking>> GetRanking(long limit, long offset)
{
var pipelines = new BsonDocument[]
var pipelines = new[]
{
new("$sort", new BsonDocument("Score.Score", -1)),
new(
"$group",
new BsonDocument
{
{ "_id", BsonNull.Value },
{ "docs", new BsonDocument("$push", "$$ROOT") },
}
),
new(
"$unwind",
new BsonDocument { { "path", "$docs" }, { "includeArrayIndex", "Rank" }, }
),
new("$skip", offset),
new("$limit", limit),
new(
"$replaceRoot",
new BsonDocument
{
{
"newRoot",
new BsonDocument
{
{
"$mergeObjects",
new BsonArray { "$docs", new BsonDocument("Rank", "$Rank"), }
},
}
},
}
),
new(
"$lookup",
new BsonDocument
{
{ "from", "avatars" },
{ "localField", "AvatarAddress" },
{ "foreignField", "Avatar.address" },
{ "as", "Avatar" },
}
),
new(
"$unwind",
new BsonDocument { { "path", "$Avatar" }, { "preserveNullAndEmptyArrays", true } }
),
};
@"{ $sort: { 'Score.Score': -1 } }",
@"{ $group: { _id: null, docs: { $push: '$$ROOT' } } }",
@"{ $unwind: { path: '$docs', includeArrayIndex: 'Rank' } }",
$@"{{ $skip: {offset} }}",
$@"{{ $limit: {limit} }}",
@"{ $replaceRoot: { newRoot: { $mergeObjects: [ '$docs', { Rank: '$Rank' } ] } } }",
@"{ $lookup: { from: 'avatars', localField: 'AvatarAddress', foreignField: 'Avatar.address', as: 'Avatar' } }",
@"{ $unwind: { path: '$Avatar', preserveNullAndEmptyArrays: true } }",
}.Select(BsonDocument.Parse).ToArray();

var aggregation = await ArenaCollection.Aggregate<dynamic>(pipelines).ToListAsync();
var aggregation = await ArenaCollection.Aggregate<BsonDocument>(pipelines).ToListAsync();

var arenaRankings = await Task.WhenAll(aggregation.OfType<BsonDocument>().Select(BuildArenaRankingFromDocument));

return arenaRankings.ToList();
}

private async Task<ArenaRanking> BuildArenaRankingFromDocument(BsonDocument document)
{
var arenaRanking = new ArenaRanking(
document["AvatarAddress"].AsString,
document["Information"]["Address"].AsString,
document["Information"]["Win"].AsInt32,
document["Information"]["Lose"].AsInt32,
document["Rank"].AsInt64 + 1,
document["Information"]["Ticket"].AsInt32,
document["Information"]["TicketResetCount"].AsInt32,
document["Information"]["PurchasedTicketCount"].AsInt32,
document["Score"]["Score"].AsInt32
);

if (!document.Contains("Avatar")) return arenaRanking;

var result = aggregation
.Select(x =>
{
var equipments = ((List<object>)x.Avatar.ItemSlot.Equipments).OfType<string>();
var costumes = ((List<object>)x.Avatar.ItemSlot.Costumes).OfType<string>();
var runeSlots = ((List<dynamic>)x.Avatar.RuneSlot).Select(rune =>
((int)rune.RuneId, (int)rune.Level)
);
var avatar = new Avatar(
document["Avatar"]["Avatar"]["address"].AsString,
document["Avatar"]["Avatar"]["name"].AsString,
document["Avatar"]["Avatar"]["level"].AsInt32
);
arenaRanking.Avatar = avatar;

var cp = CpRepository
.CalculateCp(
x.Avatar.Avatar.address,
x.Avatar.Avatar.level,
x.Avatar.Avatar.characterId,
equipments,
costumes,
runeSlots
)
.Result;
var characterId = document["Avatar"]["Avatar"]["characterId"].AsInt32;
var equipmentids = document["Avatar"]["ItemSlot"]["Equipments"].AsBsonArray.Select(x => x.AsString);
var costumeids = document["Avatar"]["ItemSlot"]["Costumes"].AsBsonArray.Select(x => x.AsString);
var runeSlots = document["Avatar"]["RuneSlot"].AsBsonArray.Select(rune =>
(rune["RuneId"].AsInt32, rune["Level"].AsInt32)
);

return new ArenaRanking(
x.AvatarAddress,
x.Information.Address,
cp,
x.Information.Win,
x.Information.Lose,
x.Rank + 1,
x.Information.Ticket,
x.Information.TicketResetCount,
x.Information.PurchasedTicketCount,
x.Score.Score,
new Avatar(x.Avatar.Avatar.address, x.Avatar.Avatar.name, x.Avatar.Avatar.level)
);
})
.ToList();
var cp = await CpRepository.CalculateCp(avatar, characterId, equipmentids, costumeids, runeSlots);
arenaRanking.CP = cp;

return result;
return arenaRanking;
}
}
63 changes: 35 additions & 28 deletions NineChroniclesUtilBackend/Repositories/CpRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,43 +7,50 @@
using Nekoyume.Model.Item;
using Nekoyume.Model.State;
using Nekoyume.TableData;
using NineChroniclesUtilBackend.Models.Agent;

namespace NineChroniclesUtilBackend.Repositories;

public static class CpRepository
{
public static async Task<int> CalculateCp(
string avatarAddress,
int avatarLevel,
public static async Task<int?> CalculateCp(
Avatar avatar,
int characterId,
IEnumerable<string> equipmentIds,
IEnumerable<string> costumeIds,
IEnumerable<(int id, int level)> runeOption
)
{
var inventory = await GetInventory(avatarAddress);
var equipments = equipmentIds
.Select(x => inventory.GetValueOrDefault(x))
.Where(x => x != null)
.Select(x => new Equipment(x))
.Where(x => x.Equipped);
var costumes = costumeIds
.Select(x => inventory.GetValueOrDefault(x))
.Where(x => x != null)
.Select(x => new Costume(x))
.Where(x => x.Equipped);
var runes = runeOption.Select(x => GetRuneOptionInfo(x.id, x.level).Result);
var characterRow = await GetCharacterRow(characterId);
var costumeStatSheet = await GetSheet(new CostumeStatSheet());

return CPHelper.TotalCP(
equipments,
costumes,
runes,
avatarLevel,
characterRow,
costumeStatSheet
);
try
{
var inventory = await GetInventory(avatar.AvatarAddress);
var equipments = equipmentIds
.Select(x => inventory.GetValueOrDefault(x))
.Where(x => x != null)
.Select(x => new Equipment(x))
.Where(x => x.Equipped);
var costumes = costumeIds
.Select(x => inventory.GetValueOrDefault(x))
.Where(x => x != null)
.Select(x => new Costume(x))
.Where(x => x.Equipped);
var runes = runeOption.Select(x => GetRuneOptionInfo(x.id, x.level).Result);
var characterRow = await GetCharacterRow(characterId);
var costumeStatSheet = await GetSheet(new CostumeStatSheet());

return CPHelper.TotalCP(
equipments,
costumes,
runes,
avatar.Level,
characterRow,
costumeStatSheet
);
}
catch (NullReferenceException)
{
return null;
}
}

private static async Task<Dictionary<string, Dictionary>> GetInventory(string address)
Expand Down Expand Up @@ -123,9 +130,9 @@ private static async Task<T> GetState<T>(Address address, string? account = null
var response = await client.GetAsync(url);
var json = JsonNode.Parse(await response.Content.ReadAsStringAsync());
var rawValue = json["value"]?.GetValue<string>();
if (rawValue == null)
if (rawValue == null || rawValue == "")
{
return default;
throw new NullReferenceException();
}
var value = codec.Decode(Convert.FromBase64String(rawValue));

Expand Down

0 comments on commit 6d7a303

Please sign in to comment.