diff --git a/Mimir/Controllers/AvatarController.cs b/Mimir/Controllers/AvatarController.cs index 07addee0..54579eb8 100644 --- a/Mimir/Controllers/AvatarController.cs +++ b/Mimir/Controllers/AvatarController.cs @@ -1,6 +1,15 @@ +using System.Numerics; +using Bencodex; +using Libplanet.Common; +using Libplanet.Crypto; using Microsoft.AspNetCore.Mvc; using Mimir.Models.Avatar; using Mimir.Repositories; +using Mimir.Services; +using Mimir.Util; +using Nekoyume.Model.State; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; namespace Mimir.Controllers; @@ -8,16 +17,107 @@ namespace Mimir.Controllers; [Route("{network}/avatars")] public class AvatarController(AvatarRepository avatarRepository) : ControllerBase { + #region temporary snippets + + // This is a snippet from Mimir/Util/BigIntegerToStringConverter.cs + private class BigIntegerToStringConverter : JsonConverter + { + public override bool CanConvert(Type objectType) + { + return objectType == typeof(BigInteger); + } + + public override object ReadJson(JsonReader reader, Type objectType, object? existingValue, + JsonSerializer serializer) + { + throw new NotImplementedException(); + } + + public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer) + { + writer.WriteValue(value?.ToString()); + } + } + + // This is a snippet from Mimir/Util/StateJsonConverter.cs + private class StateJsonConverter : JsonConverter + { + public override bool CanConvert(Type objectType) + { + return typeof(IState).IsAssignableFrom(objectType); + } + + public override object ReadJson( + JsonReader reader, + Type objectType, + object? existingValue, + JsonSerializer serializer) + { + throw new NotImplementedException(); + } + + public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer) + { + if (value is null) + { + return; + } + + var jo = JObject.FromObject(value, JsonSerializer.CreateDefault(new JsonSerializerSettings + { + ReferenceLoopHandling = ReferenceLoopHandling.Ignore, + Converters = new List { new BigIntegerToStringConverter() }, + Formatting = Formatting.Indented, + NullValueHandling = NullValueHandling.Ignore + })); + + var iValue = value switch + { + AvatarState avatarState => avatarState.SerializeList(), + IState state => state.Serialize(), + _ => null + }; + + if (iValue != null) + { + var rawValue = ByteUtil.Hex(new Codec().Encode(iValue)); + jo.Add("Raw", rawValue); + } + + jo.WriteTo(writer); + } + } + + // This is a snippet from Mimir.Worker/Models/State/BaseData.cs + private static JsonSerializerSettings JsonSerializerSettings => new() + { + Converters = { new StateJsonConverter() }, + Formatting = Formatting.Indented, + NullValueHandling = NullValueHandling.Ignore + }; + + #endregion snippets + [HttpGet("{avatarAddress}/inventory")] - public Inventory? GetInventory(string network, string avatarAddress) + public async Task GetInventory( + string network, + string avatarAddress, + IStateService stateService) { var inventory = avatarRepository.GetInventory(network, avatarAddress); - if (inventory is null) + if (inventory is not null) + { + return inventory; + } + + var stateGetter = new StateGetter(stateService); + var inventoryState = await stateGetter.GetInventoryStateAsync(new Address(avatarAddress)); + if (inventoryState is null) { Response.StatusCode = StatusCodes.Status404NotFound; return null; } - return inventory; + return new Inventory(inventoryState); } } diff --git a/Mimir/Models/Avatar/Inventory.cs b/Mimir/Models/Avatar/Inventory.cs index 64d29820..e7e48538 100644 --- a/Mimir/Models/Avatar/Inventory.cs +++ b/Mimir/Models/Avatar/Inventory.cs @@ -3,9 +3,21 @@ namespace Mimir.Models.Avatar; -public class Inventory(BsonValue inventory) +public class Inventory { - public List Equipments { get; set; } = inventory["Equipments"].AsBsonArray - .Select(e => new Equipment(e.AsBsonDocument)) - .ToList(); + public List Equipments { get; set; } + + public Inventory(Nekoyume.Model.Item.Inventory inventory) + { + Equipments = inventory.Equipments + .Select(e => new Equipment(e)) + .ToList(); + } + + public Inventory(BsonValue inventory) + { + Equipments = inventory["Equipments"].AsBsonArray + .Select(e => new Equipment(e.AsBsonDocument)) + .ToList(); + } } diff --git a/Mimir/Models/Items/Equipment.cs b/Mimir/Models/Items/Equipment.cs index 599ab3aa..7ec1d86a 100644 --- a/Mimir/Models/Items/Equipment.cs +++ b/Mimir/Models/Items/Equipment.cs @@ -2,7 +2,17 @@ namespace Mimir.Models.Items; -public class Equipment(BsonValue equipment) : NonFungibleItem(equipment) +public class Equipment : NonFungibleItem { - public int Level { get; set; } = equipment["level"].AsInt32; + public int Level { get; set; } + + public Equipment(Nekoyume.Model.Item.Equipment equipment) : base(equipment) + { + Level = equipment.level; + } + + public Equipment(BsonValue equipment) : base(equipment) + { + Level = equipment["level"].AsInt32; + } } diff --git a/Mimir/Models/Items/Item.cs b/Mimir/Models/Items/Item.cs index 98145e5e..764706dc 100644 --- a/Mimir/Models/Items/Item.cs +++ b/Mimir/Models/Items/Item.cs @@ -3,7 +3,17 @@ namespace Mimir.Models.Items; -public class Item(BsonValue item) +public class Item { - public ItemSubType ItemSubType { get; set; } = (ItemSubType)item["ItemSubType"].AsInt32; + public ItemSubType ItemSubType { get; set; } + + public Item(IItem item) + { + ItemSubType = item.ItemSubType; + } + + public Item(BsonValue item) + { + ItemSubType = (ItemSubType)item["ItemSubType"].AsInt32; + } } diff --git a/Mimir/Models/Items/NonFungibleItem.cs b/Mimir/Models/Items/NonFungibleItem.cs index 335653fa..49a1cb54 100644 --- a/Mimir/Models/Items/NonFungibleItem.cs +++ b/Mimir/Models/Items/NonFungibleItem.cs @@ -1,11 +1,21 @@ using MongoDB.Bson; +using Nekoyume.Model.Item; namespace Mimir.Models.Items; -public class NonFungibleItem(BsonValue nonFungibleItem) : Item(nonFungibleItem) +public class NonFungibleItem : Item { - public Guid NonFungibleId { get; set; } = - Guid.TryParse(nonFungibleItem["NonFungibleId"].AsString, out var nonFungibleId) + public Guid NonFungibleId { get; set; } + + public NonFungibleItem(INonFungibleItem nonFungibleItem) : base(nonFungibleItem) + { + NonFungibleId = nonFungibleItem.NonFungibleId; + } + + public NonFungibleItem(BsonValue nonFungibleItem) : base(nonFungibleItem) + { + NonFungibleId = Guid.TryParse(nonFungibleItem["NonFungibleId"].AsString, out var nonFungibleId) ? nonFungibleId : Guid.Empty; + } }