Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Handle 404 #35

Merged
merged 6 commits into from
May 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
# Created by https://www.toptal.com/developers/gitignore/api/dotnetcore,aspnetcore
# Edit at https://www.toptal.com/developers/gitignore?templates=dotnetcore,aspnetcore

# OS junk files
*.DS_Store

### ASPNETCore ###
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
Expand Down
50 changes: 9 additions & 41 deletions NineChroniclesUtilBackend/Controllers/AgentController.cs
Original file line number Diff line number Diff line change
@@ -1,18 +1,8 @@
using Microsoft.AspNetCore.Mvc;
using NineChroniclesUtilBackend.Models.Agent;
using Bencodex.Types;
using Libplanet.Crypto;
using Microsoft.AspNetCore.Mvc;
using Nekoyume;
using Nekoyume.Action;
using Nekoyume.Model.EnumType;
using Nekoyume.Model.Item;
using Nekoyume.Model.State;
using Nekoyume.TableData;
using NineChroniclesUtilBackend.Models.Arena;
using NineChroniclesUtilBackend.Services;
using NineChroniclesUtilBackend.Arena;

using NineChroniclesUtilBackend.Util;

namespace NineChroniclesUtilBackend.Controllers;

Expand All @@ -22,39 +12,17 @@ public class AccountController : ControllerBase
{
[HttpGet("{agentAddress}/avatars")]
public async Task<AvatarsResponse> GetAvatars(string agentAddress, IStateService stateService)
{
var avatarStates = await GetAvatarStates(new Address(agentAddress), stateService);
return new AvatarsResponse(avatarStates
.Select(a => new Avatar(a.address.ToString(), a.name, a.level))
.ToList());
}

private static async Task<List<AvatarState>> GetAvatarStates(Address agentAddress, IStateService stateService)
{
var rawState = await stateService.GetState(agentAddress, Addresses.Agent) ??
await stateService.GetState(agentAddress);
var agentState = rawState switch
var stateGetter = new StateGetter(stateService);
var avatars = await stateGetter.GetAvatarStatesAsync(new Address(agentAddress));
if (avatars is null)
{
Dictionary agentStateDictionary => new AgentState(agentStateDictionary),
List agentStateList => new AgentState(agentStateList),
_ => throw new ArgumentException(nameof(agentAddress)),
};

var avatars = new List<AvatarState>();
foreach(var avatarAddress in agentState.avatarAddresses.Values)
{
var rawAvatarState =
await stateService.GetState(avatarAddress, Addresses.Avatar) ??
await stateService.GetState(avatarAddress);
var avatarState = rawAvatarState switch
{
Dictionary avatarStateDictionary => new AvatarState(avatarStateDictionary),
List avatarStateList => new AvatarState(avatarStateList),
_ => throw new ArgumentException(nameof(avatarAddress))
};
avatars.Add(avatarState);
Response.StatusCode = StatusCodes.Status404NotFound;
return new AvatarsResponse([]);
}

return avatars;
return new AvatarsResponse(avatars
.Select(e => new Avatar(e.address.ToString(), e.name, e.level))
.ToList());
}
}
54 changes: 30 additions & 24 deletions NineChroniclesUtilBackend/Controllers/ArenaController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,14 @@ public class ArenaController(ArenaRankingRepository arenaRankingRepository) : Co
[HttpGet("ranking/{avatarAddress}/rank")]
public async Task<long> GetRankByAvatarAddress(string avatarAddress)
{
return await arenaRankingRepository.GetRankByAvatarAddress(avatarAddress);
var rank = await arenaRankingRepository.GetRankByAvatarAddress(avatarAddress);
if (rank == 0)
{
Response.StatusCode = StatusCodes.Status404NotFound;
return default;
}

return rank;
}

[HttpGet("ranking")]
Expand All @@ -28,19 +35,18 @@ public async Task<List<ArenaRanking>> GetRanking(int limit, int offset)
[HttpPost("simulate")]
public async Task<ArenaSimulateResponse> Simulate(
[FromBody] ArenaSimulateRequest arenaSimulateRequest,
IStateService stateService
)
IStateService stateService)
{
var stateGetter = new StateGetter(stateService);

var myAvatarAddress = new Address(arenaSimulateRequest.MyAvatarAddress);
var enemyAvatarAddress = new Address(arenaSimulateRequest.EnemyAvatarAddress);
var myAvatarState = await stateGetter.GetAvatarState(myAvatarAddress);
var myAvatarItemSlotState = await stateGetter.GetItemSlotState(myAvatarAddress);
var myAvatarRuneStates = await stateGetter.GetRuneStates(myAvatarAddress);
var enemyAvatarState = await stateGetter.GetAvatarState(enemyAvatarAddress);
var enemyAvatarItemSlotState = await stateGetter.GetItemSlotState(enemyAvatarAddress);
var enemyAvatarRuneStates = await stateGetter.GetRuneStates(enemyAvatarAddress);
var myAvatarState = await stateGetter.GetAvatarStateAsync(myAvatarAddress);
var myAvatarItemSlotState = await stateGetter.GetItemSlotStateAsync(myAvatarAddress);
var myAvatarRuneStates = await stateGetter.GetRuneStatesAsync(myAvatarAddress);
var enemyAvatarState = await stateGetter.GetAvatarStateAsync(enemyAvatarAddress);
var enemyAvatarItemSlotState = await stateGetter.GetItemSlotStateAsync(enemyAvatarAddress);
var enemyAvatarRuneStates = await stateGetter.GetRuneStatesAsync(enemyAvatarAddress);

var bulkSimulator = new ArenaBulkSimulator();
var result = await bulkSimulator.BulkSimulate(
Expand All @@ -51,22 +57,22 @@ IStateService stateService
enemyAvatarRuneStates
),
new ArenaSimulatorSheets(
await stateGetter.GetSheet<MaterialItemSheet>(),
await stateGetter.GetSheet<SkillSheet>(),
await stateGetter.GetSheet<SkillBuffSheet>(),
await stateGetter.GetSheet<StatBuffSheet>(),
await stateGetter.GetSheet<SkillActionBuffSheet>(),
await stateGetter.GetSheet<ActionBuffSheet>(),
await stateGetter.GetSheet<CharacterSheet>(),
await stateGetter.GetSheet<CharacterLevelSheet>(),
await stateGetter.GetSheet<EquipmentItemSetEffectSheet>(),
await stateGetter.GetSheet<CostumeStatSheet>(),
await stateGetter.GetSheet<WeeklyArenaRewardSheet>(),
await stateGetter.GetSheet<RuneOptionSheet>()
await stateGetter.GetSheetAsync<MaterialItemSheet>(),
await stateGetter.GetSheetAsync<SkillSheet>(),
await stateGetter.GetSheetAsync<SkillBuffSheet>(),
await stateGetter.GetSheetAsync<StatBuffSheet>(),
await stateGetter.GetSheetAsync<SkillActionBuffSheet>(),
await stateGetter.GetSheetAsync<ActionBuffSheet>(),
await stateGetter.GetSheetAsync<CharacterSheet>(),
await stateGetter.GetSheetAsync<CharacterLevelSheet>(),
await stateGetter.GetSheetAsync<EquipmentItemSetEffectSheet>(),
await stateGetter.GetSheetAsync<CostumeStatSheet>(),
await stateGetter.GetSheetAsync<WeeklyArenaRewardSheet>(),
await stateGetter.GetSheetAsync<RuneOptionSheet>()
),
await stateGetter.GetCollectionStates([myAvatarAddress, enemyAvatarAddress]),
await stateGetter.GetSheet<CollectionSheet>(),
await stateGetter.GetSheet<DeBuffLimitSheet>()
await stateGetter.GetCollectionStatesAsync([myAvatarAddress, enemyAvatarAddress]),
await stateGetter.GetSheetAsync<CollectionSheet>(),
await stateGetter.GetSheetAsync<DeBuffLimitSheet>()
);

return new ArenaSimulateResponse(result);
Expand Down
13 changes: 11 additions & 2 deletions NineChroniclesUtilBackend/Controllers/AvatarController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,15 @@ namespace NineChroniclesUtilBackend.Controllers;
public class AvatarController(AvatarRepository avatarRepository) : ControllerBase
{
[HttpGet("{avatarAddress}/inventory")]
public Inventory GetInventory(string avatarAddress) =>
avatarRepository.GetInventory(avatarAddress);
public Inventory? GetInventory(string avatarAddress)
{
var inventory = avatarRepository.GetInventory(avatarAddress);
if (inventory is null)
{
Response.StatusCode = StatusCodes.Status404NotFound;
return null;
}

return inventory;
}
}
2 changes: 0 additions & 2 deletions NineChroniclesUtilBackend/Models/Agent/Avatar.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
using MongoDB.Bson;

namespace NineChroniclesUtilBackend.Models.Agent;

public class Avatar(string avatarAddress, string avatarName, int level)
Expand Down
36 changes: 18 additions & 18 deletions NineChroniclesUtilBackend/Models/Arena/ArenaRanking.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,28 +3,28 @@
namespace NineChroniclesUtilBackend.Models.Arena;

public class ArenaRanking(
string AvatarAddress,
string ArenaAddress,
int Win,
int Lose,
long Rank,
int Ticket,
int TicketResetCount,
int PurchasedTicketCount,
int Score
string avatarAddress,
string arenaAddress,
int win,
int lose,
long rank,
int ticket,
int ticketResetCount,
int purchasedTicketCount,
int score
)
{
public string AvatarAddress { get; set; } = AvatarAddress;
public string ArenaAddress { get; set; } = ArenaAddress;
public string AvatarAddress { get; set; } = avatarAddress;
public string ArenaAddress { get; set; } = arenaAddress;
[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 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;

[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public Agent.Avatar? Avatar { get; set; }
Expand Down
29 changes: 14 additions & 15 deletions NineChroniclesUtilBackend/Repositories/ArenaRankingRespository.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
using MongoDB.Bson;
using MongoDB.Driver;
using Nekoyume.Model.State;
using NineChroniclesUtilBackend.Models.Agent;
using NineChroniclesUtilBackend.Models.Arena;
using NineChroniclesUtilBackend.Services;
Expand All @@ -9,10 +8,9 @@ namespace NineChroniclesUtilBackend.Repositories;

public class ArenaRankingRepository(MongoDBCollectionService mongoDBCollectionService, IStateService stateService)
{
private CpRepository cpRepository = new CpRepository(stateService);

private readonly IMongoCollection<dynamic> ArenaCollection =
private readonly IMongoCollection<dynamic> _arenaCollection =
mongoDBCollectionService.GetCollection<dynamic>("arena");
private readonly CpRepository _cpRepository = new(stateService);

public async Task<long> GetRankByAvatarAddress(string avatarAddress)
{
Expand All @@ -33,10 +31,10 @@ public async Task<long> GetRankByAvatarAddress(string avatarAddress)
),
new("$match", new BsonDocument("docs.AvatarAddress", avatarAddress)),
};

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

return aggregation.First().Rank;
var aggregation = await _arenaCollection.Aggregate<dynamic>(pipelines).ToListAsync();
return aggregation.Count == 0
? 0
: (long)aggregation.First().Rank;
}

public async Task<List<ArenaRanking>> GetRanking(long limit, long offset)
Expand All @@ -50,10 +48,8 @@ public async Task<List<ArenaRanking>> GetRanking(long limit, long offset)
@"{ $unwind: { path: '$Avatar', preserveNullAndEmptyArrays: true } }",
@"{ $unset: ['Avatar.Avatar.inventory', 'Avatar.Avatar.mailBox', 'Avatar.Avatar.stageMap', 'Avatar.Avatar.monsterMap', 'Avatar.Avatar.itemMap', 'Avatar.Avatar.eventMap'] }",
}.Select(BsonDocument.Parse).ToArray();

var aggregation = ArenaCollection.Aggregate<BsonDocument>(pipelines).ToList();
var aggregation = _arenaCollection.Aggregate<BsonDocument>(pipelines).ToList();
var arenaRankings = await Task.WhenAll(aggregation.OfType<BsonDocument>().Select(BuildArenaRankingFromDocument));

return [.. arenaRankings];
}

Expand All @@ -71,7 +67,10 @@ private async Task<ArenaRanking> BuildArenaRankingFromDocument(BsonDocument docu
document["Score"]["Score"].AsInt32
);

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

var avatar = new Avatar(
document["Avatar"]["Avatar"]["address"].AsString,
Expand All @@ -81,13 +80,13 @@ private async Task<ArenaRanking> BuildArenaRankingFromDocument(BsonDocument docu
arenaRanking.Avatar = avatar;

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 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)
);

var cp = await cpRepository.CalculateCp(avatar, characterId, equipmentids, costumeids, runeSlots);
var cp = await _cpRepository.CalculateCp(avatar, characterId, equipmentIds, costumeIds, runeSlots);
arenaRanking.CP = cp;
Console.WriteLine($"CP Calculate {arenaRanking.ArenaAddress}");

Expand Down
7 changes: 6 additions & 1 deletion NineChroniclesUtilBackend/Repositories/AvatarRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,16 @@ public class AvatarRepository(MongoDBCollectionService mongoDBCollectionService)
private readonly IMongoCollection<BsonDocument> _avatarsCollection =
mongoDBCollectionService.GetCollection<BsonDocument>("avatars");

public Inventory GetInventory(string avatarAddress)
public Inventory? GetInventory(string avatarAddress)
{
var filter = Builders<BsonDocument>.Filter.Eq(f => f["Avatar"]["address"], avatarAddress);
var projection = Builders<BsonDocument>.Projection.Include(f => f["Avatar"]["inventory"]["Equipments"]);
var document = _avatarsCollection.Find(filter).Project(projection).FirstOrDefault();
if (document is null)
{
return null;
}

return new Inventory(document["Avatar"]["inventory"]);
}
}
12 changes: 6 additions & 6 deletions NineChroniclesUtilBackend/Repositories/CpRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,10 @@ public CpRepository(IStateService stateService)
var avatarAddress = new Address(avatar.AvatarAddress);

var characterRow = await GetCharacterRow(characterId);
var costumeStatSheet = await _stateGetter.GetSheet<CostumeStatSheet>();
var collectionSheets = await _stateGetter.GetSheet<CollectionSheet>();
var costumeStatSheet = await _stateGetter.GetSheetAsync<CostumeStatSheet>();
var collectionSheets = await _stateGetter.GetSheetAsync<CollectionSheet>();

var inventoryState = await _stateGetter.GetInventoryState(avatarAddress);
var inventoryState = await _stateGetter.GetInventoryStateAsync(avatarAddress);

List<Equipment> equipments = inventoryState
.Equipments
Expand All @@ -45,7 +45,7 @@ public CpRepository(IStateService stateService)
.Costumes
.Where(x => x.Equipped).ToList();
List<RuneOptionSheet.Row.RuneOptionInfo> runes = runeOption.Select(x => GetRuneOptionInfo(x.id, x.level).Result).ToList();
var collectionStates = await _stateGetter.GetCollectionStates([avatarAddress]);
var collectionStates = await _stateGetter.GetCollectionStatesAsync([avatarAddress]);
var modifiers = new Dictionary<Address, List<StatModifier>>
{
[avatarAddress] = new(),
Expand Down Expand Up @@ -83,7 +83,7 @@ public CpRepository(IStateService stateService)
int level
)
{
var sheets = await _stateGetter.GetSheet<RuneOptionSheet>();
var sheets = await _stateGetter.GetSheetAsync<RuneOptionSheet>();

if (!sheets.TryGetValue(id, out var optionRow))
{
Expand All @@ -100,7 +100,7 @@ int level

private async Task<CharacterSheet.Row> GetCharacterRow(int characterId)
{
var sheets = await _stateGetter.GetSheet<CharacterSheet>();
var sheets = await _stateGetter.GetSheetAsync<CharacterSheet>();

if (!sheets.TryGetValue(characterId, out var row))
{
Expand Down
Loading