Getting ready to seed more data

This commit is contained in:
gamer147
2026-05-23 15:47:23 -04:00
parent 631e42289a
commit 5f44ee0c7e
74 changed files with 499 additions and 50 deletions

View File

@@ -171,7 +171,6 @@ public class LoadController : SVSimController
MasterPoints = 0
}).ToList(),
ArenaConfig = new ArenaConfig(),
ArenaInfos = new List<ArenaInfo>(),
RotationSets = rotationSets,
UserConfig = new UserConfig(),
OpenBattlefieldIds = (await _globalsRepository.GetBattlefields(true))

View File

@@ -1,12 +1,15 @@
using MessagePack;
using System.Text.Json.Serialization;
namespace SVSim.EmulatedEntrypoint.Models.Dtos;
[MessagePackObject]
public class ArenaConfig
{
[JsonPropertyName("use_challenge_two_pick_premium_card")]
[Key("use_challenge_two_pick_premium_card")]
public int UseChallengePickTwoPremiumCard { get; set; }
[JsonPropertyName("challenge_two_pick_sleeve_id")]
[Key("challenge_two_pick_sleeve_id")]
public int ChallengePickTwoCardSleeve { get; set; }
}

View File

@@ -1,21 +1,28 @@
using MessagePack;
using SVSim.Database.Enums;
using System.Text.Json.Serialization;
namespace SVSim.EmulatedEntrypoint.Models.Dtos;
[MessagePackObject]
public class ArenaFormatInfo
{
[JsonPropertyName("two_pick_type")]
[Key("two_pick_type")]
public PickTwoFormat PickTwoFormat { get; set; }
[JsonPropertyName("card_pool_name")]
[Key("card_pool_name")]
public string CardPoolName { get; set; } = string.Empty;
[JsonPropertyName("announce_id")]
[Key("announce_id")]
public string AnnounceId { get; set; } = "0";
[JsonPropertyName("card_pool_url")]
[Key("card_pool_url")]
public string CardPoolUrl { get; set; } = string.Empty;
[JsonPropertyName("start_time")]
[Key("start_time")]
public DateTime StartTime { get; set; }
[JsonPropertyName("end_time")]
[Key("end_time")]
public DateTime EndTime { get; set; }
}

View File

@@ -1,24 +1,33 @@
using MessagePack;
using System.Text.Json.Serialization;
namespace SVSim.EmulatedEntrypoint.Models.Dtos;
[MessagePackObject]
public class ArenaInfo
{
[JsonPropertyName("mode")]
[Key("mode")]
public int Mode { get; set; }
[JsonPropertyName("enable")]
[Key("enable")]
public int Enable { get; set; }
[JsonPropertyName("cost")]
[Key("cost")]
public ulong Cost { get; set; }
[JsonPropertyName("rupy_cost")]
[Key("rupy_cost")]
public ulong RupeeCost { get; set; }
[JsonPropertyName("ticket_cost")]
[Key("ticket_cost")]
public int TicketCost { get; set; }
[JsonPropertyName("is_join")]
[Key("is_join")]
public bool IsJoin { get; set; }
[JsonPropertyName("sales_period_info")]
[Key("sales_period_info")]
public ShopExpiryInfo? SalesPeriodInfo { get; set; }
[JsonPropertyName("format_info")]
[Key("format_info")]
public ArenaFormatInfo? FormatInfo { get; set; }
}

View File

@@ -1,26 +1,36 @@
using MessagePack;
using System.Text.Json.Serialization;
namespace SVSim.EmulatedEntrypoint.Models.Dtos;
[MessagePackObject]
public class AvatarAbility
{
[JsonPropertyName("leader_skin_id")]
[Key("leader_skin_id")]
public int LeaderSkinId { get; set; }
[JsonPropertyName("battle_start_firstplayerturn_bp")]
[Key("battle_start_firstplayerturn_bp")]
public int BattleStartFirstPlayerBp { get; set; }
[JsonPropertyName("battle_start_secondplayerturn_bp")]
[Key("battle_start_secondplayerturn_bp")]
public int BattleStartSecondPlayerBp { get; set; }
[JsonPropertyName("battle_start_max_life")]
[Key("battle_start_max_life")]
public int BattleStartMaxLife { get; set; }
[JsonPropertyName("ability_cost")]
[Key("ability_cost")]
public string AbilityCost { get; set; }
[JsonPropertyName("ability")]
[Key("ability")]
public string Ability { get; set; }
[JsonPropertyName("passive_ability")]
[Key("passive_ability")]
public string PassiveAbility { get; set; }
[JsonPropertyName("ability_desc")]
[Key("ability_desc")]
public string AbilityDesc { get; set; }
[JsonPropertyName("passive_ability_desc")]
[Key("passive_ability_desc")]
public string PassiveAbilityDesc { get; set; }
}

View File

@@ -1,12 +1,15 @@
using MessagePack;
using System.Text.Json.Serialization;
namespace SVSim.EmulatedEntrypoint.Models.Dtos;
[MessagePackObject]
public class AvatarInfo
{
[JsonPropertyName("abilities")]
[Key("abilities")]
public Dictionary<string, AvatarAbility> Abilities { get; set; } = new Dictionary<string, AvatarAbility>();
[JsonPropertyName("schedules")]
[Key("schedules")]
public SpecialRotationSchedule Schedules { get; set; } = new SpecialRotationSchedule();
}

View File

@@ -1,12 +1,15 @@
using MessagePack;
using System.Text.Json.Serialization;
namespace SVSim.EmulatedEntrypoint.Models.Dtos;
[MessagePackObject]
public class BattlePassLevel
{
[JsonPropertyName("level")]
[Key("level")]
public int Level { get; set; }
[JsonPropertyName("required_point")]
[Key("required_point")]
public int RequiredPoints { get; set; }
}

View File

@@ -1,4 +1,5 @@
using MessagePack;
using System.Text.Json.Serialization;
namespace SVSim.EmulatedEntrypoint.Models.Dtos;
@@ -11,6 +12,7 @@ public class CardIdentifier
/// <summary>
/// The identifier of the card.
/// </summary>
[JsonPropertyName("card_id")]
[Key("card_id")]
public long CardId { get; set; }
}

View File

@@ -1,10 +1,12 @@
using MessagePack;
using System.Text.Json.Serialization;
namespace SVSim.EmulatedEntrypoint.Models.Dtos;
[MessagePackObject]
public class CardSetIdentifier
{
[JsonPropertyName("card_set_id")]
[Key("card_set_id")]
public int SetId { get; set; }
}

View File

@@ -1,16 +1,21 @@
using MessagePack;
using System.Text.Json.Serialization;
namespace SVSim.EmulatedEntrypoint.Models.Dtos;
[MessagePackObject]
public class ClassExp
{
[JsonPropertyName("level")]
[Key("level")]
public int Level { get; set; }
[JsonPropertyName("necessary_exp")]
[Key("necessary_exp")]
public int NecessaryExp { get; set; }
[JsonPropertyName("diff_exp")]
[Key("diff_exp")]
public int DiffExp { get; set; }
[JsonPropertyName("accumulate_exp")]
[Key("accumulate_exp")]
public int AccumulateExp { get; set; }
}

View File

@@ -1,4 +1,5 @@
using MessagePack;
using System.Text.Json.Serialization;
namespace SVSim.EmulatedEntrypoint.Models.Dtos.Common;
@@ -10,5 +11,6 @@ namespace SVSim.EmulatedEntrypoint.Models.Dtos.Common;
[MessagePackObject]
public class EmptyResponse
{
[JsonPropertyName("_")]
[Key("_")] public object? Reserved { get; set; }
}

View File

@@ -1,4 +1,5 @@
using MessagePack;
using System.Text.Json.Serialization;
namespace SVSim.EmulatedEntrypoint.Models.Dtos.Common;
@@ -9,7 +10,10 @@ namespace SVSim.EmulatedEntrypoint.Models.Dtos.Common;
[MessagePackObject]
public class Reward
{
[JsonPropertyName("type")]
[Key("type")] public int? Type { get; set; }
[JsonPropertyName("value")]
[Key("value")] public long? Value { get; set; }
[JsonPropertyName("num")]
[Key("num")] public int? Num { get; set; }
}

View File

@@ -1,14 +1,18 @@
using MessagePack;
using System.Text.Json.Serialization;
namespace SVSim.EmulatedEntrypoint.Models.Dtos;
[MessagePackObject]
public class DailyLoginBonus
{
[JsonPropertyName("total")]
[Key("total")]
public LoginBonusCampaign? Total { get; set; }
[JsonPropertyName("normal")]
[Key("normal")]
public LoginBonusCampaign? Normal { get; set; }
[JsonPropertyName("campaign")]
[Key("campaign")]
public LoginBonusCampaign? Campaign { get; set; }
}

View File

@@ -1,12 +1,15 @@
using MessagePack;
using System.Text.Json.Serialization;
namespace SVSim.EmulatedEntrypoint.Models.Dtos;
[MessagePackObject]
public class DateRange
{
[JsonPropertyName("begin_time")]
[Key("begin_time")]
public DateTime BeginTime { get; set; }
[JsonPropertyName("end_time")]
[Key("end_time")]
public DateTime EndTime { get; set; }
}

View File

@@ -1,15 +1,19 @@
using MessagePack;
using SVSim.Database.Models;
using System.Text.Json.Serialization;
namespace SVSim.EmulatedEntrypoint.Models.Dtos;
[MessagePackObject]
public class DefaultSettings
{
[JsonPropertyName("default_emblem_id")]
[Key("default_emblem_id")]
public int DefaultEmblemId { get; set; }
[JsonPropertyName("default_degree_id")]
[Key("default_degree_id")]
public int DefaultDegreeId { get; set; }
[JsonPropertyName("default_mypage_id")]
[Key("default_mypage_id")]
public int DefaultMyPageBackground { get; set; }

View File

@@ -1,10 +1,12 @@
using MessagePack;
using System.Text.Json.Serialization;
namespace SVSim.EmulatedEntrypoint.Models.Dtos;
[MessagePackObject]
public class DegreeIdentifier
{
[JsonPropertyName("degree_id")]
[Key("degree_id")]
public int DegreeId { get; set; }
}

View File

@@ -1,10 +1,12 @@
using MessagePack;
using System.Text.Json.Serialization;
namespace SVSim.EmulatedEntrypoint.Models.Dtos;
[MessagePackObject]
public class EmblemIdentifier
{
[JsonPropertyName("emblem_id")]
[Key("emblem_id")]
public long EmblemId { get; set; }
}

View File

@@ -1,10 +1,12 @@
using MessagePack;
using System.Text.Json.Serialization;
namespace SVSim.EmulatedEntrypoint.Models.Dtos;
[MessagePackObject]
public class GatheringInfo
{
[JsonPropertyName("has_invite")]
[Key("has_invite")]
public int HasInvite { get; set; }
}

View File

@@ -1,18 +1,24 @@
using MessagePack;
using System.Text.Json.Serialization;
namespace SVSim.EmulatedEntrypoint.Models.Dtos.Internal;
[MessagePackObject]
public class DataHeaders
{
[JsonPropertyName("short_udid")]
[Key("short_udid")]
public long ShortUdid { get; set; }
[JsonPropertyName("viewer_id")]
[Key("viewer_id")]
public long ViewerId { get; set; }
[JsonPropertyName("sid")]
[Key("sid")]
public string Sid { get; set; }
[JsonPropertyName("servertime")]
[Key("servertime")]
public long Servertime { get; set; }
[JsonPropertyName("result_code")]
[Key("result_code")]
public int ResultCode { get; set; }
}

View File

@@ -1,4 +1,5 @@
using MessagePack;
using System.Text.Json.Serialization;
namespace SVSim.EmulatedEntrypoint.Models.Dtos.Internal;
@@ -11,12 +12,14 @@ public class DataWrapper
/// <summary>
/// Additional data about the request, response and user.
/// </summary>
[JsonPropertyName("data_headers")]
[Key("data_headers")]
public DataHeaders DataHeaders { get; set; } = new DataHeaders();
/// <summary>
/// The response data from the endpoint.
/// </summary>
[JsonPropertyName("data")]
[Key("data")]
public object Data { get; set; } = new();
}

View File

@@ -1,20 +1,27 @@
using MessagePack;
using System.Text.Json.Serialization;
namespace SVSim.EmulatedEntrypoint.Models.Dtos;
[MessagePackObject]
public class LoginBonusCampaign
{
[JsonPropertyName("name")]
[Key("name")]
public string Name { get; set; } = string.Empty;
[JsonPropertyName("campaign_id")]
[Key("campaign_id")]
public int CampaignId { get; set; }
[JsonPropertyName("img")]
[Key("img")]
public int Image { get; set; }
[JsonPropertyName("now_count")]
[Key("now_count")]
public int NowCount { get; set; }
[JsonPropertyName("is_next_reward")]
[Key("is_next_reward")]
public bool IsNextReward { get; set; }
[JsonPropertyName("reward")]
[Key("reward")]
public List<LoginBonusReward> Rewards { get; set; } = new List<LoginBonusReward>();
}

View File

@@ -1,4 +1,5 @@
using MessagePack;
using System.Text.Json.Serialization;
namespace SVSim.EmulatedEntrypoint.Models.Dtos;
@@ -8,24 +9,28 @@ public class LoginBonusReward
/// <summary>
/// The effect shown ingame.
/// </summary>
[JsonPropertyName("effect_id")]
[Key("effect_id")]
public int EffectId { get; set; }
/// <summary>
/// The type of reward.
/// </summary>
[JsonPropertyName("reward_type")]
[Key("reward_type")]
public int RewardType { get; set; }
/// <summary>
/// A more specified reward type (ie if a pack, which pack).
/// </summary>
[JsonPropertyName("reward_detail_id")]
[Key("reward_detail_id")]
public int RewardDetailId { get; set; }
/// <summary>
/// The count of the reward.
/// </summary>
[JsonPropertyName("reward_number")]
[Key("reward_number")]
public int RewardNumber { get; set; }
}

View File

@@ -1,4 +1,5 @@
using MessagePack;
using System.Text.Json.Serialization;
namespace SVSim.EmulatedEntrypoint.Models.Dtos;
@@ -8,16 +9,22 @@ namespace SVSim.EmulatedEntrypoint.Models.Dtos;
[MessagePackObject]
public class LootBoxRegulations
{
[JsonPropertyName("pack")]
[Key("pack")]
public int Pack { get; set; }
[JsonPropertyName("arena_2pick")]
[Key("arena_2pick")]
public int ArenaPickTwo { get; set; }
[JsonPropertyName("arena_sealed")]
[Key("arena_sealed")]
public int ArenaSealed { get; set; }
[JsonPropertyName("arena_colosseum")]
[Key("arena_colosseum")]
public int ArenaColosseum { get; set; }
[JsonPropertyName("arena_competition")]
[Key("arena_competition")]
public int ArenaCompetition { get; set; }
[JsonPropertyName("special_shop")]
[Key("special_shop")]
public int SpecialShop { get; set; }
}

View File

@@ -1,22 +1,30 @@
using MessagePack;
using System.Text.Json.Serialization;
namespace SVSim.EmulatedEntrypoint.Models.Dtos;
[MessagePackObject()]
public class MyRotationAbility
{
[JsonPropertyName("ability_id")]
[Key("ability_id")]
public int AbilityId { get; set; }
[JsonPropertyName("add_start_pp")]
[Key("add_start_pp")]
public int AddStartPp { get; set; }
[JsonPropertyName("add_start_life")]
[Key("add_start_life")]
public int AddStartLife { get; set; }
[JsonPropertyName("increase_add_pptotal_amount")]
[Key("increase_add_pptotal_amount")]
public int IncreaseAddPpTotalAmount { get; set; }
[JsonPropertyName("increase_add_pptotal_turn")]
[Key("increase_add_pptotal_turn")]
public int IncreaseAddPpTotalTurn { get; set; }
[JsonPropertyName("ability")]
[Key("ability")]
public string Ability { get; set; } = string.Empty;
[JsonPropertyName("ability_desc")]
[Key("ability_desc")]
public string AbilityDesc { get; set; } = string.Empty;
}

View File

@@ -1,22 +1,28 @@
using MessagePack;
using System.Text.Json.Serialization;
namespace SVSim.EmulatedEntrypoint.Models.Dtos;
[MessagePackObject]
public class MyRotationInfo
{
[JsonPropertyName("abilities")]
[Key("abilities")]
public Dictionary<string, MyRotationAbility> Abilities { get; set; } = new Dictionary<string, MyRotationAbility>();
[JsonPropertyName("schedules")]
[Key("schedules")]
public SpecialRotationSchedule Schedules { get; set; } = new SpecialRotationSchedule();
[JsonPropertyName("setting")]
[Key("setting")]
public Dictionary<string, SpecialRotationSetting>? Settings { get; set; }
[JsonPropertyName("disabled_card_set_ids")]
[Key("disabled_card_set_ids")]
public List<int>? DisabledCardSets { get; set; }
/// <summary>
/// Set to card to card reprinted list.
/// </summary>
[JsonPropertyName("reprinted_base_card_ids")]
[Key("reprinted_base_card_ids")]
public Dictionary<string, Dictionary<string, int>>? ReprintedCards { get; set; }
@@ -24,6 +30,7 @@ public class MyRotationInfo
/// <summary>
/// Set to card to count banlist.
/// </summary>
[JsonPropertyName("restricted_base_card_id_list")]
[Key("restricted_base_card_id_list")]
public Dictionary<string, Dictionary<string, int>>? Banlist { get; set; }
}

View File

@@ -1,36 +1,51 @@
using MessagePack;
using System.Text.Json.Serialization;
namespace SVSim.EmulatedEntrypoint.Models.Dtos;
[MessagePackObject]
public class PreReleaseInfo
{
[JsonPropertyName("id")]
[Key("id")]
public int Id { get; set; }
[JsonPropertyName("start_time")]
[Key("start_time")]
public DateTime StartTime { get; set; }
[JsonPropertyName("end_time")]
[Key("end_time")]
public DateTime EndTime { get; set; }
[JsonPropertyName("display_end_time")]
[Key("display_end_time")]
public DateTime DisplayEndTime { get; set; }
[JsonPropertyName("next_card_set_id")]
[Key("next_card_set_id")]
public int NextCardSetId { get; set; }
[JsonPropertyName("default_card_master_id")]
[Key("default_card_master_id")]
public int DefaultCardMasterId { get; set; }
[JsonPropertyName("pre_release_card_master_id")]
[Key("pre_release_card_master_id")]
public int PreReleaseCardMasterId { get; set; }
[JsonPropertyName("free_match_start_time")]
[Key("free_match_start_time")]
public DateTime FreeMatchStartTime { get; set; }
[JsonPropertyName("card_master_id")]
[Key("card_master_id")]
public int CardMasterId { get; set; }
[JsonPropertyName("rotation_card_set_id_list")]
[Key("rotation_card_set_id_list")]
public List<int> RotationCardSets { get; set; } = new List<int>();
[JsonPropertyName("reprinted_base_card_ids")]
[Key("reprinted_base_card_ids")]
public Dictionary<string, long> ReprintedCardIds { get; set; } = new Dictionary<string, long>();
[JsonPropertyName("latest_reprinted_base_card_ids")]
[Key("latest_reprinted_base_card_ids")]
public List<int> LatestReprintedCardIds { get; set; } = new List<int>();
[JsonPropertyName("pre_release_status")]
[Key("pre_release_status")]
public int PreReleaseStatus { get; set; }
[JsonPropertyName("is_pre_rotation_free_match_term")]
[Key("is_pre_rotation_free_match_term")]
public int IsPreRotationFreeMatchTerm { get; set; }
}

View File

@@ -1,43 +1,61 @@
using MessagePack;
using SVSim.Database.Models;
using System.Text.Json.Serialization;
namespace SVSim.EmulatedEntrypoint.Models.Dtos;
[MessagePackObject]
public class RankInfo
{
[JsonPropertyName("rank_id")]
[Key("rank_id")]
public int RankId { get; set; }
[JsonPropertyName("rank_name")]
[Key("rank_name")]
public string RankName { get; set; } = string.Empty;
[JsonPropertyName("necessary_point")]
[Key("necessary_point")]
public int NecessaryPoints { get; set; }
[JsonPropertyName("accumulate_point")]
[Key("accumulate_point")]
public int AccumulatePoints { get; set; }
[JsonPropertyName("lower_limit_point")]
[Key("lower_limit_point")]
public int LowerLimitPoints { get; set; }
[JsonPropertyName("base_add_bp")]
[Key("base_add_bp")]
public int BaseAddBp { get; set; }
[JsonPropertyName("base_drop_bp")]
[Key("base_drop_bp")]
public int BaseDropBp { get; set; }
[JsonPropertyName("streak_bonus_pt")]
[Key("streak_bonus_pt")]
public int StreakBonusPoints { get; set; }
[JsonPropertyName("win_bonus")]
[Key("win_bonus")]
public double WinBonus { get; set; }
[JsonPropertyName("lose_bonus")]
[Key("lose_bonus")]
public double LoseBonus { get; set; }
[JsonPropertyName("max_win_bonus")]
[Key("max_win_bonus")]
public int MaxWinBonus { get; set; }
[JsonPropertyName("max_lose_bonus")]
[Key("max_lose_bonus")]
public int MaxLoseBonus { get; set; }
[JsonPropertyName("is_promotion_war")]
[Key("is_promotion_war")]
public int IsPromotionWar { get; set; }
[JsonPropertyName("match_count")]
[Key("match_count")]
public int MatchCount { get; set; }
[JsonPropertyName("necessary_win")]
[Key("necessary_win")]
public int NecessaryWins { get; set; }
[JsonPropertyName("reset_lose")]
[Key("reset_lose")]
public int ResetLose { get; set; }
[JsonPropertyName("accumulate_master_point")]
[Key("accumulate_master_point")]
public int AccumulateMasterPoints { get; set; }

View File

@@ -1,4 +1,5 @@
using MessagePack;
using System.Text.Json.Serialization;
namespace SVSim.EmulatedEntrypoint.Models.Dtos;
@@ -11,18 +12,21 @@ public class RedEtherOverride
/// <summary>
/// The id of the affected card.
/// </summary>
[JsonPropertyName("card_id")]
[Key("card_id")]
public ulong CardId { get; set; }
/// <summary>
/// How much red ether is now provided from dusting the card.
/// </summary>
[JsonPropertyName("get_red_ether")]
[Key("get_red_ether")]
public int GetRedEther { get; set; }
/// <summary>
/// How much red ether is now required to craft the card.
/// </summary>
[JsonPropertyName("use_red_ether")]
[Key("use_red_ether")]
public int UseRedEther { get; set; }
}

View File

@@ -1,14 +1,18 @@
using MessagePack;
using System.Text.Json.Serialization;
namespace SVSim.EmulatedEntrypoint.Models.Dtos.Requests;
[MessagePackObject]
public class BaseRequest
{
[JsonPropertyName("viewer_id")]
[Key("viewer_id")]
public string ViewerId { get; set; }
[JsonPropertyName("steam_id")]
[Key("steam_id")]
public ulong SteamId { get; set; }
[JsonPropertyName("steam_session_ticket")]
[Key("steam_session_ticket")]
public string SteamSessionTicket { get; set; }
}

View File

@@ -1,4 +1,5 @@
using MessagePack;
using System.Text.Json.Serialization;
namespace SVSim.EmulatedEntrypoint.Models.Dtos.Requests.Common;
@@ -9,5 +10,6 @@ namespace SVSim.EmulatedEntrypoint.Models.Dtos.Requests.Common;
[MessagePackObject]
public class DeckFormatRequest : BaseRequest
{
[JsonPropertyName("deck_format")]
[Key("deck_format")] public int DeckFormat { get; set; }
}

View File

@@ -1,10 +1,13 @@
using MessagePack;
using System.Text.Json.Serialization;
namespace SVSim.EmulatedEntrypoint.Models.Dtos.Requests.Deck;
[MessagePackObject]
public class DeckDeleteListRequest : BaseRequest
{
[JsonPropertyName("deck_no_list")]
[Key("deck_no_list")] public List<int>? DeckNoList { get; set; }
[JsonPropertyName("deck_format")]
[Key("deck_format")] public int DeckFormat { get; set; }
}

View File

@@ -1,10 +1,11 @@
using MessagePack;
using SVSim.EmulatedEntrypoint.Models.Dtos.Requests.Common;
using System.Text.Json.Serialization;
namespace SVSim.EmulatedEntrypoint.Models.Dtos.Requests.Deck;
/// <summary>
/// /deck/info standard request is `DeckFormatRequest`. Copy-source overload adds
/// /deck/info 窶・standard request is `DeckFormatRequest`. Copy-source overload adds
/// `create_deck_format` (the format the user is creating the new deck IN). Server can
/// ignore create_deck_format and return the standard shape; only matters for the
/// cross-format deck-copy UI flow.
@@ -12,5 +13,6 @@ namespace SVSim.EmulatedEntrypoint.Models.Dtos.Requests.Deck;
[MessagePackObject]
public class DeckInfoRequest : DeckFormatRequest
{
[JsonPropertyName("create_deck_format")]
[Key("create_deck_format")] public int? CreateDeckFormat { get; set; }
}

View File

@@ -1,10 +1,13 @@
using MessagePack;
using System.Text.Json.Serialization;
namespace SVSim.EmulatedEntrypoint.Models.Dtos.Requests.Deck;
[MessagePackObject]
public class DeckOrderRequest : BaseRequest
{
[JsonPropertyName("deck_order")]
[Key("deck_order")] public List<int>? DeckOrder { get; set; }
[JsonPropertyName("deck_format")]
[Key("deck_format")] public int DeckFormat { get; set; }
}

View File

@@ -1,11 +1,15 @@
using MessagePack;
using System.Text.Json.Serialization;
namespace SVSim.EmulatedEntrypoint.Models.Dtos.Requests.Deck;
[MessagePackObject]
public class DeckUpdateLeaderSkinRequest : BaseRequest
{
[JsonPropertyName("deck_no")]
[Key("deck_no")] public int DeckNo { get; set; }
[JsonPropertyName("leader_skin_id")]
[Key("leader_skin_id")] public int LeaderSkinId { get; set; }
[JsonPropertyName("deck_format")]
[Key("deck_format")] public int DeckFormat { get; set; }
}

View File

@@ -1,11 +1,15 @@
using MessagePack;
using System.Text.Json.Serialization;
namespace SVSim.EmulatedEntrypoint.Models.Dtos.Requests.Deck;
[MessagePackObject]
public class DeckUpdateNameRequest : BaseRequest
{
[JsonPropertyName("deck_no")]
[Key("deck_no")] public int DeckNo { get; set; }
[JsonPropertyName("deck_name")]
[Key("deck_name")] public string? DeckName { get; set; }
[JsonPropertyName("deck_format")]
[Key("deck_format")] public int DeckFormat { get; set; }
}

View File

@@ -1,11 +1,15 @@
using MessagePack;
using System.Text.Json.Serialization;
namespace SVSim.EmulatedEntrypoint.Models.Dtos.Requests.Deck;
[MessagePackObject]
public class DeckUpdateRandomLeaderSkinRequest : BaseRequest
{
[JsonPropertyName("deck_format")]
[Key("deck_format")] public int DeckFormat { get; set; }
[JsonPropertyName("deck_no")]
[Key("deck_no")] public int DeckNo { get; set; }
[JsonPropertyName("leader_skin_id_list")]
[Key("leader_skin_id_list")] public List<int>? LeaderSkinIdList { get; set; }
}

View File

@@ -1,27 +1,40 @@
using MessagePack;
using System.Text.Json.Serialization;
namespace SVSim.EmulatedEntrypoint.Models.Dtos.Requests.Deck;
[MessagePackObject]
public class DeckUpdateRequest : BaseRequest
{
[JsonPropertyName("deck_no")]
[Key("deck_no")] public int DeckNo { get; set; }
[JsonPropertyName("class_id")]
[Key("class_id")] public int ClassId { get; set; }
[JsonPropertyName("leader_skin_id")]
[Key("leader_skin_id")] public int LeaderSkinId { get; set; }
[JsonPropertyName("is_random_leader_skin")]
[Key("is_random_leader_skin")] public bool IsRandomLeaderSkin { get; set; }
[JsonPropertyName("leader_skin_id_list")]
[Key("leader_skin_id_list")] public List<int>? LeaderSkinIdList { get; set; }
[JsonPropertyName("sleeve_id")]
[Key("sleeve_id")] public long SleeveId { get; set; }
[JsonPropertyName("deck_name")]
[Key("deck_name")] public string? DeckName { get; set; }
/// <summary>0 = save the deck, 1 = delete this deck slot.</summary>
[JsonPropertyName("is_delete")]
[Key("is_delete")] public int IsDelete { get; set; }
[JsonPropertyName("card_id_array")]
[Key("card_id_array")] public List<long>? CardIdArray { get; set; }
[JsonPropertyName("deck_format")]
[Key("deck_format")] public int DeckFormat { get; set; }
/// <summary>MyRotation rule-set id (only when deck_format = MyRotation).</summary>
[JsonPropertyName("rotation_id")]
[Key("rotation_id")] public string? RotationId { get; set; }
/// <summary>Crossover sub-class id (only when deck_format = Crossover).</summary>
[JsonPropertyName("sub_class_id")]
[Key("sub_class_id")] public int? SubClassId { get; set; }
}

View File

@@ -1,11 +1,15 @@
using MessagePack;
using System.Text.Json.Serialization;
namespace SVSim.EmulatedEntrypoint.Models.Dtos.Requests.Deck;
[MessagePackObject]
public class DeckUpdateSleeveRequest : BaseRequest
{
[JsonPropertyName("deck_no")]
[Key("deck_no")] public int DeckNo { get; set; }
[JsonPropertyName("sleeve_id")]
[Key("sleeve_id")] public long SleeveId { get; set; }
[JsonPropertyName("deck_format")]
[Key("deck_format")] public int DeckFormat { get; set; }
}

View File

@@ -1,10 +1,13 @@
using MessagePack;
using System.Text.Json.Serialization;
namespace SVSim.EmulatedEntrypoint.Models.Dtos.Requests.Deck;
[MessagePackObject]
public class SetDeckRedisRequest : BaseRequest
{
[JsonPropertyName("deck_no")]
[Key("deck_no")] public int DeckNo { get; set; }
[JsonPropertyName("class_id")]
[Key("class_id")] public int ClassId { get; set; }
}

View File

@@ -1,16 +1,21 @@
using MessagePack;
using System.Text.Json.Serialization;
namespace SVSim.EmulatedEntrypoint.Models.Dtos.Requests;
[MessagePackObject]
public class GameStartRequest : BaseRequest
{
[JsonPropertyName("app_type")]
[Key("app_type")]
public int AppType { get; set; }
[JsonPropertyName("campaign_data")]
[Key("campaign_data")]
public string CampaignData { get; set; }
[JsonPropertyName("campaign_sign")]
[Key("campaign_sign")]
public string CampaignSign { get; set; }
[JsonPropertyName("campaign_user")]
[Key("campaign_user")]
public int CampaignUser { get; set; }
}

View File

@@ -1,13 +1,16 @@
using MessagePack;
using System.Text.Json.Serialization;
namespace SVSim.EmulatedEntrypoint.Models.Dtos.Requests;
[MessagePackObject]
public class IndexRequest : BaseRequest
{
[JsonPropertyName("carrier")]
[Key("carrier")]
public string Carrier { get; set; }
[JsonPropertyName("card_master_hash")]
[Key("card_master_hash")]
public string CardMasterHash { get; set; }
}

View File

@@ -1,30 +1,42 @@
using MessagePack;
using System.Text.Json.Serialization;
namespace SVSim.EmulatedEntrypoint.Models.Dtos.Requests.Practice;
[MessagePackObject]
public class PracticeFinishRequest : BaseRequest
{
[JsonPropertyName("deck_no")]
[Key("deck_no")] public int DeckNo { get; set; }
[JsonPropertyName("is_win")]
[Key("is_win")] public int IsWin { get; set; }
[JsonPropertyName("evolve_count")]
[Key("evolve_count")] public int EvolveCount { get; set; }
[JsonPropertyName("total_turn")]
[Key("total_turn")] public int TotalTurn { get; set; }
[JsonPropertyName("enemy_class_id")]
[Key("enemy_class_id")] public int EnemyClassId { get; set; }
[JsonPropertyName("difficulty")]
[Key("difficulty")] public int Difficulty { get; set; }
[JsonPropertyName("deck_format")]
[Key("deck_format")] public int DeckFormat { get; set; }
[JsonPropertyName("class_id")]
[Key("class_id")] public int ClassId { get; set; }
[JsonPropertyName("mission")]
[Key("mission")] public Dictionary<string, int>? Mission { get; set; }
/// <summary>
/// JSON blob `recovery_single.json` serialized to string. Always present; not validated
/// JSON blob 窶・`recovery_single.json` serialized to string. Always present; not validated
/// server-side (audit-flagged as out of scope for v1).
/// </summary>
[JsonPropertyName("recovery_data")]
[Key("recovery_data")] public string? RecoveryData { get; set; }
/// <summary>
/// Misspelled the same way in every solo finish endpoint preserved on the wire.
/// Misspelled the same way in every solo finish endpoint 窶・preserved on the wire.
/// See spec note on practice-finish.md.
/// </summary>
[JsonPropertyName("prosessing_time_data")]
[Key("prosessing_time_data")] public List<string>? ProsessingTimeData { get; set; }
}

View File

@@ -1,15 +1,17 @@
using MessagePack;
using System.Text.Json.Serialization;
namespace SVSim.EmulatedEntrypoint.Models.Dtos.Responses.Deck;
/// <summary>
/// Shape consumed by `DeckGroupListData(jsonData, format)` for a single-format call
/// the format-scoped decks land under `user_deck_list` (vs. the per-format keys used
/// Shape consumed by `DeckGroupListData(jsonData, format)` for a single-format call 窶・/// the format-scoped decks land under `user_deck_list` (vs. the per-format keys used
/// by /practice/deck_list with Format.All).
/// </summary>
[MessagePackObject]
public class DeckListResponse
{
[JsonPropertyName("maintenance_card_list")]
[Key("maintenance_card_list")] public List<long> MaintenanceCardList { get; set; } = new();
[JsonPropertyName("user_deck_list")]
[Key("user_deck_list")] public List<UserDeck>? UserDeckList { get; set; }
}

View File

@@ -1,5 +1,6 @@
using MessagePack;
using SVSim.EmulatedEntrypoint.Models.Dtos.Common;
using System.Text.Json.Serialization;
namespace SVSim.EmulatedEntrypoint.Models.Dtos.Responses.Deck;
@@ -11,7 +12,10 @@ namespace SVSim.EmulatedEntrypoint.Models.Dtos.Responses.Deck;
[MessagePackObject]
public class DeckUpdateResponse
{
[JsonPropertyName("user_deck_list")]
[Key("user_deck_list")] public List<UserDeck>? UserDeckList { get; set; }
[JsonPropertyName("achieved_info")]
[Key("achieved_info")] public Dictionary<string, object> AchievedInfo { get; set; } = new();
[JsonPropertyName("reward_list")]
[Key("reward_list")] public List<Reward> RewardList { get; set; } = new();
}

View File

@@ -1,4 +1,5 @@
using MessagePack;
using System.Text.Json.Serialization;
namespace SVSim.EmulatedEntrypoint.Models.Dtos.Responses.Deck;
@@ -6,5 +7,6 @@ namespace SVSim.EmulatedEntrypoint.Models.Dtos.Responses.Deck;
public class EmptyDeckNumberResponse
{
/// <summary>The next free deck slot number. 0 indicates "no slots available".</summary>
[JsonPropertyName("empty_deck_num")]
[Key("empty_deck_num")] public int EmptyDeckNum { get; set; }
}

View File

@@ -1,15 +1,17 @@
using MessagePack;
using System.Text.Json.Serialization;
namespace SVSim.EmulatedEntrypoint.Models.Dtos.Responses.Deck;
/// <summary>
/// Single-deck-update response. Consumed by DeckListUtility.DeckUpdate(user_deck,
/// format, DeckAttributeType.CustomDeck). Shape is "one UserDeck wrapped under
/// `user_deck` key" same for update_name, update_sleeve, update_leader_skin,
/// `user_deck` key" 窶・same for update_name, update_sleeve, update_leader_skin,
/// update_random_leader_skin.
/// </summary>
[MessagePackObject]
public class SingleDeckResponse
{
[JsonPropertyName("user_deck")]
[Key("user_deck")] public UserDeck? UserDeck { get; set; }
}

View File

@@ -1,11 +1,12 @@
using MessagePack;
using System.Text.Json.Serialization;
namespace SVSim.EmulatedEntrypoint.Models.Dtos.Responses;
/// <summary>
/// Wire-shape mirrors production's <c>/check/game_start</c> response. Several fields here are
/// NOT read by <c>Cute/GameStartCheckTask.Parse</c> (<c>now_viewer_id</c>, <c>now_name</c>,
/// <c>now_rank</c> those are consumed by sibling tasks); they're included because prod sends
/// <c>now_rank</c> 窶・those are consumed by sibling tasks); they're included because prod sends
/// them and the boot worked when we matched prod exactly. Removing them is a regression risk
/// even though the parse-time decompile says they're unused.
/// </summary>
@@ -13,6 +14,7 @@ namespace SVSim.EmulatedEntrypoint.Models.Dtos.Responses;
public class GameStartResponse
{
/// <summary>The signed-in viewer's internal id. Prod always sends.</summary>
[JsonPropertyName("now_viewer_id")]
[Key("now_viewer_id")]
public long NowViewerId { get; set; }
@@ -20,10 +22,12 @@ public class GameStartResponse
/// Whether the user has set a data-transfer password. Prod sends a non-null bool;
/// <c>GameStartCheckTask.Parse</c> gates the read with <c>Keys.Contains</c>.
/// </summary>
[JsonPropertyName("is_set_transition_password")]
[Key("is_set_transition_password")]
public bool IsSetTransitionPassword { get; set; }
/// <summary>Viewer display name. Not read by GameStartCheckTask but sent by prod.</summary>
[JsonPropertyName("now_name")]
[Key("now_name")]
public string NowName { get; set; } = string.Empty;
@@ -32,60 +36,71 @@ public class GameStartResponse
/// Stub for now until rank state is persisted; pinned to RankName_010 / RankName_017
/// (matches prod's shape).
/// </summary>
[JsonPropertyName("now_rank")]
[Key("now_rank")]
public Dictionary<string, string> NowRank { get; set; } = new();
/// <summary>
/// Tutorial progress **sent as a string on the wire** ("100" = tutorial complete).
/// Tutorial progress 窶・**sent as a string on the wire** ("100" = tutorial complete).
/// <c>GameStartCheckTask.Parse</c> calls <c>.ToInt()</c> so LitJson coerces.
/// </summary>
[JsonPropertyName("now_tutorial_step")]
[Key("now_tutorial_step")]
public string NowTutorialStep { get; set; } = "100";
/// <summary>
/// Linked social accounts. Per-entry shape in <see cref="TransitionAccountData"/>.
/// </summary>
[JsonPropertyName("transition_account_data")]
[Key("transition_account_data")]
public List<TransitionAccountData> TransitionAccountData { get; set; } = new();
/// <summary>
/// When present, client overwrites <c>Certification.ViewerId</c> with this value. Optional
/// leave null to omit. The serialization pipeline (JSON + msgpack via the translation
/// 窶・leave null to omit. The serialization pipeline (JSON + msgpack via the translation
/// middleware) drops null properties end-to-end, so the client sees the key as absent.
/// </summary>
[JsonPropertyName("rewrite_viewer_id")]
[Key("rewrite_viewer_id")]
public long? RewriteViewerId { get; set; }
/// <summary>
/// Presence indicates the user has applied for account deletion (value ignored by client at
/// this stage). Optional leave null to omit.
/// this stage). Optional 窶・leave null to omit.
/// </summary>
[JsonPropertyName("account_delete_reservation_status")]
[Key("account_delete_reservation_status")]
public int? AccountDeleteReservationStatus { get; set; }
// --- Agreement / consent state (all required) ---
/// <summary><c>PlayerStaticData.AgreementState</c> enum.</summary>
[JsonPropertyName("tos_state")]
[Key("tos_state")]
public int TosState { get; set; }
/// <summary><c>PlayerStaticData.AgreementState</c> enum.</summary>
[JsonPropertyName("policy_state")]
[Key("policy_state")]
public int PolicyState { get; set; }
/// <summary><c>PlayerStaticData.AgreementState</c> enum.</summary>
[JsonPropertyName("kor_authority_state")]
[Key("kor_authority_state")]
public int KorAuthorityState { get; set; }
/// <summary>Current Terms of Service document id.</summary>
[JsonPropertyName("tos_id")]
[Key("tos_id")]
public int TosId { get; set; }
/// <summary>Current Privacy Policy document id.</summary>
[JsonPropertyName("policy_id")]
[Key("policy_id")]
public int PolicyId { get; set; }
/// <summary>Current Korean authority consent document id.</summary>
[JsonPropertyName("kor_authority_id")]
[Key("kor_authority_id")]
public int KorAuthorityId { get; set; }
}

View File

@@ -1,5 +1,6 @@
using MessagePack;
using SVSim.Database.Enums;
using System.Text.Json.Serialization;
namespace SVSim.EmulatedEntrypoint.Models.Dtos.Responses;
@@ -8,20 +9,28 @@ public class IndexResponse
{
#region Primitive Returns
[JsonPropertyName("spot_point")]
[Key("spot_point")]
public int SpotPoint { get; set; }
[JsonPropertyName("is_available_colosseum_free_entry")]
[Key("is_available_colosseum_free_entry")]
public bool IsAvailableColosseumFreeEntry { get; set; }
[JsonPropertyName("friend_battle_invite_count")]
[Key("friend_battle_invite_count")]
public int FriendBattleInviteCount { get; set; }
[JsonPropertyName("battle_recovery_status")]
[Key("battle_recovery_status")]
public int BattleRecoveryStatus { get; set; }
[JsonPropertyName("room_recovery_status")]
[Key("room_recovery_status")]
public int RoomRecoveryStatus { get; set; }
[JsonPropertyName("is_battle_pass_period")]
[Key("is_battle_pass_period")]
public int IsBattlePassPeriod { get; set; }
[JsonPropertyName("card_set_id_for_resource_dl_view")]
[Key("card_set_id_for_resource_dl_view")]
public int CardSetIdForResourceDlView { get; set; }
[JsonPropertyName("deck_format")]
[Key("deck_format")]
public int DeckFormat { get; set; } = 1;
@@ -29,12 +38,15 @@ public class IndexResponse
#region Basic User Data
[JsonPropertyName("user_tutorial")]
[Key("user_tutorial")]
public UserTutorial UserTutorial { get; set; } = new UserTutorial();
[JsonPropertyName("user_info")]
[Key("user_info")]
public UserInfo UserInfo { get; set; } = new UserInfo();
[JsonPropertyName("user_crystal_count")]
[Key("user_crystal_count")]
public UserCurrency UserCurrency { get; set; } = new UserCurrency();
@@ -42,45 +54,56 @@ public class IndexResponse
#region Inventory Data
[JsonPropertyName("user_item_list")]
[Key("user_item_list")]
public List<UserItem> UserItems { get; set; } = new();
[JsonPropertyName("user_deck_rotation")]
[Key("user_deck_rotation")]
public UserFormatDeckInfo UserRotationDecks { get; set; } = new();
[JsonPropertyName("user_deck_unlimited")]
[Key("user_deck_unlimited")]
public UserFormatDeckInfo UserUnlimitedDecks { get; set; } = new();
[JsonPropertyName("user_deck_my_rotation")]
[Key("user_deck_my_rotation")]
public UserFormatDeckInfo UserMyRotationDecks { get; set; } = new();
[JsonPropertyName("user_card_list")]
[Key("user_card_list")]
public List<UserCard> UserCards { get; set; } = new();
[JsonPropertyName("user_class_list")]
[Key("user_class_list")]
public List<UserClass> UserClasses { get; set; } = new();
/// <summary>
/// Wire is an array; parser iterates by index (LoadDetail.cs:358-360).
/// </summary>
[JsonPropertyName("user_sleeve_list")]
[Key("user_sleeve_list")]
public List<SleeveIdentifier> Sleeves { get; set; } = new();
[JsonPropertyName("user_emblem_list")]
[Key("user_emblem_list")]
public List<EmblemIdentifier> UserEmblems { get; set; } = new();
[JsonPropertyName("user_degree_list")]
[Key("user_degree_list")]
public List<DegreeIdentifier> UserDegrees { get; set; } = new();
/// <summary>
/// Wire is an array; parser iterates by index (LoadDetail.cs:348-356).
/// </summary>
[JsonPropertyName("user_leader_skin_list")]
[Key("user_leader_skin_list")]
public List<UserLeaderSkin> LeaderSkins { get; set; } = new();
/// <summary>
/// Wire is string[]; parser calls .ToString() on each element (LoadDetail.cs:387-392).
/// </summary>
[JsonPropertyName("user_mypage_list")]
[Key("user_mypage_list")]
public List<string> MyPageBackgrounds { get; set; } = new();
@@ -92,15 +115,19 @@ public class IndexResponse
/// Wire is an array of 5 entries; parser uses deck_format as discriminator
/// (LoadDetail.cs:527-538).
/// </summary>
[JsonPropertyName("user_rank")]
[Key("user_rank")]
public List<UserRankInfo> UserRankInfo { get; set; } = new();
[JsonPropertyName("user_rank_match_list")]
[Key("user_rank_match_list")]
public List<UserRankedMatches> UserRankedMatches { get; set; } = new();
[JsonPropertyName("daily_login_bonus")]
[Key("daily_login_bonus")]
public DailyLoginBonus DailyLoginBonus { get; set; } = new();
[JsonPropertyName("challenge_config")]
[Key("challenge_config")]
public ArenaConfig ArenaConfig { get; set; } = new();
@@ -108,6 +135,7 @@ public class IndexResponse
#region Global Data
[JsonPropertyName("red_ether_overwrite_list")]
[Key("red_ether_overwrite_list")]
public List<RedEtherOverride> RedEtherOverrides { get; set; } = new();
@@ -115,71 +143,94 @@ public class IndexResponse
/// Wire is a flat number[]; parser passes it straight to SetMaintenanceCardIds
/// (LoadDetail.cs:165).
/// </summary>
[JsonPropertyName("maintenance_card_list")]
[Key("maintenance_card_list")]
public List<long> MaintenanceCards { get; set; } = new();
/// <summary>
/// Client's ArenaData(JsonData) ctor reads data[0] unconditionally inside the
/// LoadDetail.cs:261 Keys.Contains("arena_info") branch — an empty list crashes
/// /load/index with ArgumentOutOfRangeException. Send null (omitted on wire) when
/// there's no arena to advertise.
/// </summary>
[JsonPropertyName("arena_info")]
[Key("arena_info")]
public List<ArenaInfo> ArenaInfos { get; set; } = new();
public List<ArenaInfo>? ArenaInfos { get; set; }
/// <summary>
/// Wire is an array; client uses POSITIONAL logic (index >= 24 = master ranks,
/// LoadDetail.cs:417-422). Order must match repository's ordering.
/// </summary>
[JsonPropertyName("rank_info")]
[Key("rank_info")]
public List<RankInfo> RankInfo { get; set; } = new();
/// <summary>
/// Wire is an array; parser iterates by index (LoadDetail.cs:425-434).
/// </summary>
[JsonPropertyName("class_exp")]
[Key("class_exp")]
public List<ClassExp> ClassExp { get; set; } = new();
[JsonPropertyName("loading_exclusion_card_list")]
[Key("loading_exclusion_card_list")]
public List<long> LoadingTipCardExclusions { get; set; } = new();
[JsonPropertyName("default_setting")]
[Key("default_setting")]
public DefaultSettings DefaultSettings { get; set; } = new();
[JsonPropertyName("unlimited_restricted_base_card_id_list")]
[Key("unlimited_restricted_base_card_id_list")]
public Dictionary<string, int> UnlimitedBanList { get; set; } = new();
/// <summary>
/// Client unconditionally accesses [1] and [Count-1] (LoadDetail.cs:184) list MUST
/// Client unconditionally accesses [1] and [Count-1] (LoadDetail.cs:184) 窶・list MUST
/// have at least 2 entries or the client crashes.
/// </summary>
[JsonPropertyName("rotation_card_set_id_list")]
[Key("rotation_card_set_id_list")]
public List<CardSetIdentifier> RotationSets { get; set; } = new();
/// <summary>
/// Wire is a flat number[]; parser iterates and reads .ToInt() (LoadDetail.cs:463-468).
/// </summary>
[JsonPropertyName("reprinted_base_card_ids")]
[Key("reprinted_base_card_ids")]
public List<long> ReprintedCards { get; set; } = new();
[JsonPropertyName("spot_cards")]
[Key("spot_cards")]
public Dictionary<string, int> SpotCards { get; set; } = new();
[JsonPropertyName("pre_release_info")]
[Key("pre_release_info")]
public PreReleaseInfo? PreReleaseInfo { get; set; }
[JsonPropertyName("my_rotation_info")]
[Key("my_rotation_info")]
public MyRotationInfo? MyRotationInfo { get; set; }
[JsonPropertyName("avatar_info")]
[Key("avatar_info")]
public MyRotationInfo? AvatarRotationInfo { get; set; }
[JsonPropertyName("feature_maintenance_list")]
[Key("feature_maintenance_list")]
public List<FeatureMaintenance> FeatureMaintenances { get; set; } = new();
[JsonPropertyName("special_crystal_info")]
[Key("special_crystal_info")]
public List<SpecialCrystalInfo> SpecialCrystalInfos { get; set; } = new();
[JsonPropertyName("battle_pass_level_info")]
[Key("battle_pass_level_info")]
public Dictionary<string, BattlePassLevel>? BattlePassLevelInfo { get; set; }
/// <summary>
/// Wire is string[]; parser calls .ToString() on each element (LoadDetail.cs:493-499).
/// </summary>
[JsonPropertyName("open_battle_field_id_list")]
[Key("open_battle_field_id_list")]
public List<string> OpenBattlefieldIds { get; set; } = new();
@@ -187,9 +238,11 @@ public class IndexResponse
#region Misc Data
[JsonPropertyName("loot_box_regulation")]
[Key("loot_box_regulation")]
public LootBoxRegulations LootBoxRegulations { get; set; } = new();
[JsonPropertyName("gathering_info")]
[Key("gathering_info")]
public GatheringInfo GatheringInfo { get; set; } = new();
@@ -197,6 +250,7 @@ public class IndexResponse
/// Spec is unclear whether this is returned at /load/index or only at /config/* endpoints
/// (load-index.md line 390). Pending live-capture confirmation; harmless extra.
/// </summary>
[JsonPropertyName("user_config")]
[Key("user_config")]
public UserConfig UserConfig { get; set; } = new();

View File

@@ -1,21 +1,25 @@
using MessagePack;
using System.Text.Json.Serialization;
namespace SVSim.EmulatedEntrypoint.Models.Dtos.Responses.Practice;
/// <summary>
/// Same shape consumed by DeckGroupListData(jsonData, Format.All). Per-format keys are
/// conditional omit (don't send empty arrays) for formats the server doesn't enable.
/// conditional 窶・omit (don't send empty arrays) for formats the server doesn't enable.
/// </summary>
[MessagePackObject]
public class PracticeDeckListResponse
{
/// <summary>Card ids currently disabled for maintenance (client unions with global list).</summary>
[JsonPropertyName("maintenance_card_list")]
[Key("maintenance_card_list")] public List<long> MaintenanceCardList { get; set; } = new();
[JsonPropertyName("user_deck_rotation")]
[Key("user_deck_rotation")] public List<UserDeck>? UserDeckRotation { get; set; }
[JsonPropertyName("user_deck_unlimited")]
[Key("user_deck_unlimited")] public List<UserDeck>? UserDeckUnlimited { get; set; }
// The remaining format keys (pre_rotation, crossover, my_rotation, avatar, default_deck_list,
// trial_deck_list, crossover_trial_deck_list, build_deck_list, user_leader_skin_setting_list)
// are all conditional added when those formats are enabled.
// are all conditional 窶・added when those formats are enabled.
}

View File

@@ -1,5 +1,6 @@
using MessagePack;
using SVSim.EmulatedEntrypoint.Models.Dtos.Common;
using System.Text.Json.Serialization;
namespace SVSim.EmulatedEntrypoint.Models.Dtos.Responses.Practice;
@@ -7,20 +8,25 @@ namespace SVSim.EmulatedEntrypoint.Models.Dtos.Responses.Practice;
public class PracticeFinishResponse
{
/// <summary>Class XP gained this match.</summary>
[JsonPropertyName("get_class_experience")]
[Key("get_class_experience")] public int GetClassExperience { get; set; }
/// <summary>Total accumulated class XP for the played class after this match.</summary>
[JsonPropertyName("class_experience")]
[Key("class_experience")] public int ClassExperience { get; set; }
/// <summary>Class level after this match (post-promotion if XP rolled over).</summary>
[JsonPropertyName("class_level")]
[Key("class_level")] public int ClassLevel { get; set; } = 1;
/// <summary>
/// Missions / achievements / rewards rollup. Empty dict means "nothing accumulated"
/// (spec: parser tolerates empty object).
/// </summary>
[JsonPropertyName("achieved_info")]
[Key("achieved_info")] public Dictionary<string, object> AchievedInfo { get; set; } = new();
/// <summary>Standard reward grants applied to user's inventory. Empty by default.</summary>
[JsonPropertyName("reward_list")]
[Key("reward_list")] public List<Reward> RewardList { get; set; } = new();
}

View File

@@ -1,4 +1,5 @@
using MessagePack;
using System.Text.Json.Serialization;
namespace SVSim.EmulatedEntrypoint.Models.Dtos.Responses.Practice;
@@ -6,38 +7,49 @@ namespace SVSim.EmulatedEntrypoint.Models.Dtos.Responses.Practice;
public class PracticeOpponent
{
/// <summary>Practice slot id (unique per entry; AI opponent identifier).</summary>
[JsonPropertyName("practice_id")]
[Key("practice_id")] public int PracticeId { get; set; }
/// <summary>
/// Text-table id resolved client-side via Data.Master.GetPracticeText(text_id).
/// Stringified int client calls .ToString() before lookup. Sent as string to be safe.
/// Stringified int 窶・client calls .ToString() before lookup. Sent as string to be safe.
/// </summary>
[JsonPropertyName("text_id")]
[Key("text_id")] public string TextId { get; set; } = string.Empty;
/// <summary>Class (leader) id the AI plays.</summary>
[JsonPropertyName("class_id")]
[Key("class_id")] public int ClassId { get; set; }
/// <summary>Portrait / character id (which leader art the AI uses).</summary>
[JsonPropertyName("chara_id")]
[Key("chara_id")] public int CharaId { get; set; }
/// <summary>Title-degree id shown next to the AI's name.</summary>
[JsonPropertyName("degree_id")]
[Key("degree_id")] public int DegreeId { get; set; }
/// <summary>AI deck-strength tier (drives which preset deck the AI uses).</summary>
[JsonPropertyName("ai_deck_level")]
[Key("ai_deck_level")] public int AiDeckLevel { get; set; }
/// <summary>AI decision-making tier.</summary>
[JsonPropertyName("ai_logic_level")]
[Key("ai_logic_level")] public int AiLogicLevel { get; set; }
/// <summary>Starting HP for the AI side (often 20).</summary>
[JsonPropertyName("ai_max_life")]
[Key("ai_max_life")] public int AiMaxLife { get; set; } = 20;
/// <summary>3D battle-field asset id (string on the wire; client int.TryParse's it).</summary>
[JsonPropertyName("battle3dfield_id")]
[Key("battle3dfield_id")] public string Battle3dFieldId { get; set; } = "1";
/// <summary>Optional. true => entry disabled, client prepends maintenance suffix.</summary>
[JsonPropertyName("is_maintenance")]
[Key("is_maintenance")] public bool? IsMaintenance { get; set; }
/// <summary>true => entry is a special "campaign" practice (event-tied).</summary>
[JsonPropertyName("is_campaign_practice")]
[Key("is_campaign_practice")] public bool IsCampaignPractice { get; set; }
}

View File

@@ -1,4 +1,5 @@
using MessagePack;
using System.Text.Json.Serialization;
namespace SVSim.EmulatedEntrypoint.Models.Dtos.Responses.Practice;
@@ -8,7 +9,8 @@ public class PracticeStartResponse
/// <summary>
/// Optional mission/achievement evaluation snapshot. Spec: safe to omit entirely;
/// client tolerates absence (defensive `Keys.Contains` check). Always null in our
/// minimal impl we don't model missions.
/// minimal impl 窶・we don't model missions.
/// </summary>
[JsonPropertyName("mission_parameter")]
[Key("mission_parameter")] public object? MissionParameter { get; set; }
}

View File

@@ -1,4 +1,5 @@
using MessagePack;
using System.Text.Json.Serialization;
namespace SVSim.EmulatedEntrypoint.Models.Dtos.Responses;
@@ -9,6 +10,7 @@ public class SpecialTitleCheckResponse
/// Numeric string. "0"/"1" are the built-in default title screens; any other value
/// is treated as an asset-bundle id. When omitted, the client defaults to "0".
/// </summary>
[JsonPropertyName("title_image_id")]
[Key("title_image_id")]
public string? TitleImageId { get; set; }
}

View File

@@ -1,12 +1,15 @@
using MessagePack;
using System.Text.Json.Serialization;
namespace SVSim.EmulatedEntrypoint.Models.Dtos;
[MessagePackObject]
public class ShopExpiryInfo
{
[JsonPropertyName("sales_period_time")]
[Key("sales_period_time")]
public DateTime? SalesPeriodTime { get; set; }
[JsonPropertyName("sales_period_series")]
[Key("sales_period_series")]
public int? SalesPeriodSeries { get; set; }
}

View File

@@ -1,4 +1,5 @@
using MessagePack;
using System.Text.Json.Serialization;
namespace SVSim.EmulatedEntrypoint.Models.Dtos;
@@ -11,6 +12,7 @@ public class SleeveIdentifier
/// <summary>
/// The id of the sleeve.
/// </summary>
[JsonPropertyName("sleeve_id")]
[Key("sleeve_id")]
public long SleeveId { get; set; }
}

View File

@@ -1,12 +1,15 @@
using MessagePack;
using System.Text.Json.Serialization;
namespace SVSim.EmulatedEntrypoint.Models.Dtos;
[MessagePackObject]
public class SpecialRotationSchedule
{
[JsonPropertyName("gathering")]
[Key("gathering")]
public DateRange Gathering { get; set; } = new DateRange();
[JsonPropertyName("free_battle")]
[Key("free_battle")]
public DateRange FreeBattle { get; set; } = new DateRange();
}

View File

@@ -1,22 +1,26 @@
using MessagePack;
using System.Text.Json.Serialization;
namespace SVSim.EmulatedEntrypoint.Models.Dtos;
[MessagePackObject]
public class SpecialRotationSetting
{
[JsonPropertyName("rotation_id")]
[Key("rotation_id")]
public int RotationId { get; set; }
/// <summary>
/// Formatted as 'setid|setid|setid...'.
/// </summary>
[JsonPropertyName("card_set_ids")]
[Key("card_set_ids")]
public string CardSetIds { get; set; }
/// <summary>
/// Formatted as 'abilityid|abilityid|abilityid...'.
/// </summary>
[JsonPropertyName("abilities")]
[Key("abilities")]
public string Abilities { get; set; }
}

View File

@@ -1,4 +1,5 @@
using MessagePack;
using System.Text.Json.Serialization;
namespace SVSim.EmulatedEntrypoint.Models.Dtos;
@@ -6,7 +7,7 @@ namespace SVSim.EmulatedEntrypoint.Models.Dtos;
/// Per-link entry in <c>transition_account_data</c>. Production sends three string fields per
/// entry even though <c>GameStartCheckTask.Parse</c> only reads <c>social_account_type</c>.
/// The extra two are read by adjacent tasks (<c>GetGameDataByTransitionCode</c>,
/// <c>GetGameDataBySocialAccountTask</c>) kept here so the wire matches prod regardless of
/// <c>GetGameDataBySocialAccountTask</c>) 窶・kept here so the wire matches prod regardless of
/// which task ends up consuming the payload.
/// </summary>
[MessagePackObject]
@@ -15,22 +16,25 @@ public class TransitionAccountData
/// <summary>
/// The social provider's account id (e.g. SteamID as a string). Sent as string on the wire.
/// </summary>
[JsonPropertyName("social_account_id")]
[Key("social_account_id")]
public string? SocialAccountId { get; set; }
/// <summary>
/// <c>Cute/CuteNetworkDefine.ACCOUNT_TYPE</c> enum, **sent as string** on the wire even
/// though it's numeric. <c>GameStartCheckTask.Parse</c> calls <c>.ToInt()</c> on it so
/// LitJson coerces transparently but matching prod's string form makes us safer against
/// LitJson coerces transparently 窶・but matching prod's string form makes us safer against
/// future client paths that might compare it as a literal.
/// 1=GooglePlay, 2=GameCenter, 3=Facebook, 4=DMM, 5=Steam, 6=AppleID.
/// </summary>
[JsonPropertyName("social_account_type")]
[Key("social_account_type")]
public string? SocialAccountType { get; set; }
/// <summary>
/// The viewer id this social connection is linked to. Sent as string.
/// </summary>
[JsonPropertyName("connected_viewer_id")]
[Key("connected_viewer_id")]
public string? ConnectedViewerId { get; set; }
}

View File

@@ -1,5 +1,6 @@
using MessagePack;
using SVSim.Database.Models;
using System.Text.Json.Serialization;
namespace SVSim.EmulatedEntrypoint.Models.Dtos;
@@ -12,12 +13,14 @@ public class UserCard : CardIdentifier
/// <summary>
/// The number of the specified card the user has.
/// </summary>
[JsonPropertyName("number")]
[Key("number")]
public int Count { get; set; }
/// <summary>
/// Whether the card is protected from dusting.
/// </summary>
[JsonPropertyName("is_protected")]
[Key("is_protected")]
public int IsProtected { get; set; }

View File

@@ -1,32 +1,41 @@
using MessagePack;
using SVSim.Database.Models;
using System.Text.Json.Serialization;
namespace SVSim.EmulatedEntrypoint.Models.Dtos;
[MessagePackObject]
public class UserClass
{
[JsonPropertyName("class_id")]
[Key("class_id")]
public int ClassId { get; set; }
[JsonPropertyName("is_available")]
[Key("is_available")]
public int IsAvailable { get; set; }
[JsonPropertyName("level")]
[Key("level")]
public int Level { get; set; }
[JsonPropertyName("exp")]
[Key("exp")]
public int Exp { get; set; }
[JsonPropertyName("is_random_leader_skin")]
[Key("is_random_leader_skin")]
public int IsRandomLeaderSkin { get; set; }
[JsonPropertyName("leader_skin_id")]
[Key("leader_skin_id")]
public int LeaderSkinId { get; set; }
[JsonPropertyName("leader_skin_id_list")]
[Key("leader_skin_id_list")]
public List<int> LeaderSkinIds { get; set; } = new List<int>();
[JsonPropertyName("default_leader_skin_id")]
[Key("default_leader_skin_id")]
public int DefaultLeaderSkinId { get; set; }

View File

@@ -1,22 +1,30 @@
using MessagePack;
using System.Text.Json.Serialization;
namespace SVSim.EmulatedEntrypoint.Models.Dtos;
[MessagePackObject]
public class UserConfig
{
[JsonPropertyName("receive_invitation")]
[Key("receive_invitation")]
public int ReceiveInvitation { get; set; }
[JsonPropertyName("receive_invitation_in_battle")]
[Key("receive_invitation_in_battle")]
public int ReceiveInvitationInBattle { get; set; }
[JsonPropertyName("receive_invitation_in_offline")]
[Key("receive_invitation_in_offline")]
public int ReceiveInvitationInOffline { get; set; }
[JsonPropertyName("receive_friend_apply")]
[Key("receive_friend_apply")]
public int ReceiveFriendApply { get; set; }
[JsonPropertyName("is_allow_send_adjust")]
[Key("is_allow_send_adjust")]
public int IsAllowSendAdjust { get; set; }
[JsonPropertyName("is_foil_preferred")]
[Key("is_foil_preferred")]
public int IsFoilPreferred { get; set; }
[JsonPropertyName("is_prize_preferred")]
[Key("is_prize_preferred")]
public int IsPrizePreferred { get; set; }
}

View File

@@ -1,31 +1,43 @@
using MessagePack;
using SVSim.Database.Models;
using System.Text.Json.Serialization;
namespace SVSim.EmulatedEntrypoint.Models.Dtos;
[MessagePackObject]
public class UserCurrency
{
[JsonPropertyName("viewer_id")]
[Key("viewer_id")]
public long ViewerId { get; set; }
[JsonPropertyName("crystal")]
[Key("crystal")]
public ulong Crystals { get; set; }
[JsonPropertyName("crystal_android")]
[Key("crystal_android")]
public ulong AndroidCrystals { get; set; }
[JsonPropertyName("crystal_ios")]
[Key("crystal_ios")]
public ulong IosCrystals { get; set; }
[JsonPropertyName("crystal_steam")]
[Key("crystal_steam")]
public ulong SteamCrystals { get; set; }
[JsonPropertyName("crystal_dmm")]
[Key("crystal_dmm")]
public ulong DmmCrystals { get; set; }
[JsonPropertyName("free_crystal")]
[Key("free_crystal")]
public ulong FreeCrystals { get; set; }
[JsonPropertyName("total_crystal")]
[Key("total_crystal")]
public ulong TotalCrystals { get; set; }
[JsonPropertyName("life_total_crystal")]
[Key("life_total_crystal")]
public ulong LifeTotalCrystals { get; set; }
[JsonPropertyName("red_ether")]
[Key("red_ether")]
public ulong RedEther { get; set; }
[JsonPropertyName("rupy")]
[Key("rupy")]
public ulong Rupees { get; set; }

View File

@@ -1,5 +1,6 @@
using MessagePack;
using SVSim.Database.Models;
using System.Text.Json.Serialization;
namespace SVSim.EmulatedEntrypoint.Models.Dtos;
@@ -9,34 +10,49 @@ namespace SVSim.EmulatedEntrypoint.Models.Dtos;
[MessagePackObject]
public class UserDeck
{
[JsonPropertyName("deck_no")]
[Key("deck_no")]
public int DeckNumber { get; set; }
[JsonPropertyName("class_id")]
[Key("class_id")]
public int ClassId { get; set; }
[JsonPropertyName("sleeve_id")]
[Key("sleeve_id")]
public int SleeveId { get; set; }
[JsonPropertyName("leader_skin_id")]
[Key("leader_skin_id")]
public int LeaderSkinId { get; set; }
[JsonPropertyName("deck_name")]
[Key("deck_name")]
public string Name { get; set; } = string.Empty;
[JsonPropertyName("card_id_array")]
[Key("card_id_array")]
public List<long> Cards { get; set; } = new List<long>();
[JsonPropertyName("is_complete_deck")]
[Key("is_complete_deck")]
public int IsCompleteDeck { get; set; }
[JsonPropertyName("restricted_card_exists")]
[Key("restricted_card_exists")]
public bool RestrictedCardExists { get; set; }
[JsonPropertyName("is_available_deck")]
[Key("is_available_deck")]
public int IsAvailable { get; set; }
[JsonPropertyName("maintenance_card_ids")]
[Key("maintenance_card_ids")]
public List<long> MaintenanceCards { get; set; } = new List<long>();
[JsonPropertyName("is_include_un_possession_card")]
[Key("is_include_un_possession_card")]
public bool IncludesNonCollectibleCards { get; set; }
[JsonPropertyName("is_random_leader_skin")]
[Key("is_random_leader_skin")]
public int IsRandomLeaderSkin { get; set; }
[JsonPropertyName("leader_skin_id_list")]
[Key("leader_skin_id_list")]
public List<int> LeaderSkinIds { get; set; } = new List<int> { 0 };
[JsonPropertyName("order_num")]
[Key("order_num")]
public int Order { get; set; }
[JsonPropertyName("create_deck_time")]
[Key("create_deck_time")]
public DateTime DeckCreateTime { get; set; }

View File

@@ -1,13 +1,16 @@
using MessagePack;
using System.Text.Json.Serialization;
namespace SVSim.EmulatedEntrypoint.Models.Dtos;
[MessagePackObject]
public class UserFormatDeckInfo
{
[JsonPropertyName("format")]
[Key("format")]
public string Format { get; set; } = string.Empty;
[JsonPropertyName("user_deck_list")]
[Key("user_deck_list")]
public List<UserDeck> UserDecks { get; set; } = new List<UserDeck>();
}

View File

@@ -1,39 +1,53 @@
using MessagePack;
using SVSim.Database.Models;
using System.Text.Json.Serialization;
namespace SVSim.EmulatedEntrypoint.Models.Dtos;
[MessagePackObject]
public class UserInfo
{
[JsonPropertyName("device_type")]
[Key("device_type")]
public int DeviceType { get; set; }
[JsonPropertyName("name")]
[Key("name")]
public string Name { get; set; } = string.Empty;
[JsonPropertyName("country_code")]
[Key("country_code")]
public string CountryCode { get; set; } = string.Empty;
[JsonPropertyName("max_friend")]
[Key("max_friend")]
public int MaxFriend { get; set; }
[JsonPropertyName("last_play_time")]
[Key("last_play_time")]
public DateTime LastPlayTime { get; set; }
[JsonPropertyName("is_received_two_pick_mission")]
[Key("is_received_two_pick_mission")]
public int HasReceivedPickTwoMission { get; set; }
/// <summary>
/// Birth date as yyyy-MM-dd. Parser does .ToString() on this field (LoadDetail.cs:203).
/// Format verified against live capture pending.
/// </summary>
[JsonPropertyName("birth")]
[Key("birth")]
public string Birthday { get; set; } = string.Empty;
[JsonPropertyName("selected_emblem_id")]
[Key("selected_emblem_id")]
public long SelectedEmblemId { get; set; }
[JsonPropertyName("selected_degree_id")]
[Key("selected_degree_id")]
public int SelectedDegreeId { get; set; }
[JsonPropertyName("mission_change_time")]
[Key("mission_change_time")]
public DateTime MissionChangeTime { get; set; }
[JsonPropertyName("mission_receive_type")]
[Key("mission_receive_type")]
public int MissionReceiveType { get; set; }
[JsonPropertyName("is_official")]
[Key("is_official")]
public int IsOfficial { get; set; }
[JsonPropertyName("is_official_mark_displayed")]
[Key("is_official_mark_displayed")]
public int IsOfficialMarkDisplayed { get; set; }

View File

@@ -1,14 +1,17 @@
using MessagePack;
using SVSim.Database.Models;
using System.Text.Json.Serialization;
namespace SVSim.EmulatedEntrypoint.Models.Dtos;
[MessagePackObject]
public class UserItem
{
[JsonPropertyName("item_id")]
[Key("item_id")]
public int ItemId { get; set; }
[JsonPropertyName("number")]
[Key("number")]
public int Number { get; set; }

View File

@@ -1,19 +1,25 @@
using MessagePack;
using SVSim.Database.Models;
using System.Text.Json.Serialization;
namespace SVSim.EmulatedEntrypoint.Models.Dtos;
[MessagePackObject]
public class UserLeaderSkin
{
[JsonPropertyName("leader_skin_id")]
[Key("leader_skin_id")]
public int Id { get; set; }
[JsonPropertyName("leader_skin_name")]
[Key("leader_skin_name")]
public string Name { get; set; } = string.Empty;
[JsonPropertyName("class_id")]
[Key("class_id")]
public int ClassId { get; set; }
[JsonPropertyName("emote_id")]
[Key("emote_id")]
public int EmoteId { get; set; }
[JsonPropertyName("is_owned")]
[Key("is_owned")]
public bool IsOwned { get; set; }
@@ -21,7 +27,7 @@ public class UserLeaderSkin
{
this.Id = leaderSkin.Id;
this.Name = leaderSkin.Name;
// Class is nullable BaseDataSeeder maps CSV class_chara_id=0 to null. Fall back to
// Class is nullable 窶・BaseDataSeeder maps CSV class_chara_id=0 to null. Fall back to
// the FK column (also nullable) and finally 0 for class-agnostic skins.
this.ClassId = leaderSkin.Class?.Id ?? leaderSkin.ClassId ?? 0;
this.EmoteId = leaderSkin.EmoteId;

View File

@@ -1,16 +1,21 @@
using MessagePack;
using System.Text.Json.Serialization;
namespace SVSim.EmulatedEntrypoint.Models.Dtos;
[MessagePackObject]
public class UserPromotionMatch
{
[JsonPropertyName("match_count")]
[Key("match_count")]
public int MatchCount { get; set; }
[JsonPropertyName("battle_result")]
[Key("battle_result")]
public int BattleResult { get; set; }
[JsonPropertyName("win")]
[Key("win")]
public int Wins { get; set; }
[JsonPropertyName("lose")]
[Key("lose")]
public int Losses { get; set; }
}

View File

@@ -1,34 +1,48 @@
using MessagePack;
using System.Text.Json.Serialization;
namespace SVSim.EmulatedEntrypoint.Models.Dtos;
[MessagePackObject]
public class UserRankInfo
{
[JsonPropertyName("deck_format")]
[Key("deck_format")]
public int DeckFormat { get; set; }
[JsonPropertyName("rank")]
[Key("rank")]
public int Rank { get; set; }
[JsonPropertyName("battle_point")]
[Key("battle_point")]
public int BattlePoints { get; set; }
[JsonPropertyName("successive_win_number")]
[Key("successive_win_number")]
public int WinStreak { get; set; }
[JsonPropertyName("successive_losses_number")]
[Key("successive_losses_number")]
public int LossStreak { get; set; }
[JsonPropertyName("is_promotion")]
[Key("is_promotion")]
public int IsPromotion { get; set; }
[JsonPropertyName("is_master_rank")]
[Key("is_master_rank")]
public int IsMasterRank { get; set; }
[JsonPropertyName("is_grand_master_rank")]
[Key("is_grand_master_rank")]
public int IsGrandMasterRank { get; set; }
[JsonPropertyName("master_point")]
[Key("master_point")]
public int MasterPoints { get; set; }
[JsonPropertyName("period_grand_master_point")]
[Key("period_grand_master_point")]
public int PeriodGrandMasterPoints { get; set; }
[JsonPropertyName("target_grand_master_point")]
[Key("target_grand_master_point")]
public int TargetGrandMasterPoints { get; set; }
[JsonPropertyName("current_grand_master_point")]
[Key("current_grand_master_point")]
public int CurrentGrandMasterPoints { get; set; }
[JsonPropertyName("user_promotion_match")]
[Key("user_promotion_match")]
public UserPromotionMatch? UserPromotionMatch { get; set; }
}

View File

@@ -1,18 +1,24 @@
using MessagePack;
using System.Text.Json.Serialization;
namespace SVSim.EmulatedEntrypoint.Models.Dtos;
[MessagePackObject]
public class UserRankedMatches
{
[JsonPropertyName("class_id")]
[Key("class_id")]
public int ClassId { get; set; }
[JsonPropertyName("match_count")]
[Key("match_count")]
public int MatchCount { get; set; }
[JsonPropertyName("win")]
[Key("win")]
public int Wins { get; set; }
[JsonPropertyName("lose")]
[Key("lose")]
public int Losses { get; set; }
[JsonPropertyName("viewer_id")]
[Key("viewer_id")]
public ulong ViewerId { get; set; }
}

View File

@@ -1,4 +1,5 @@
using MessagePack;
using System.Text.Json.Serialization;
namespace SVSim.EmulatedEntrypoint.Models.Dtos;
@@ -11,6 +12,7 @@ public class UserTutorial
/// <summary>
/// The current tutorial step they are on.
/// </summary>
[JsonPropertyName("tutorial_step")]
[Key("tutorial_step")]
public int TutorialStep { get; set; }
}

View File

@@ -10,9 +10,9 @@ using SVSim.UnitTests.Infrastructure;
namespace SVSim.UnitTests.Controllers;
/// <summary>
/// Coverage for <c>/deck/*</c> — the deck-editor CRUD surface. Plain-JSON path; the
/// camelCase'd C# property names are what tests see (see the note on Phase 6 / encrypted
/// pipeline for the msgpack contract).
/// Coverage for <c>/deck/*</c> — the deck-editor CRUD surface. Tests assert against the
/// <c>[Key("...")]</c>-driven wire keys (mirrored to <c>[JsonPropertyName]</c>); these are
/// the names the decompiled client actually parses, NOT <c>SnakeCaseLower(C# property)</c>.
/// </summary>
public class DeckControllerTests
{
@@ -53,7 +53,7 @@ public class DeckControllerTests
Assert.That(decks.GetArrayLength(), Is.EqualTo(2),
"Only Rotation-format decks should be returned for a Rotation request.");
var names = Enumerable.Range(0, decks.GetArrayLength())
.Select(i => decks[i].GetProperty("name").GetString())
.Select(i => decks[i].GetProperty("deck_name").GetString())
.ToList();
Assert.That(names, Is.EquivalentTo(new[] { "Slot 1", "Slot 2" }));
}
@@ -74,7 +74,7 @@ public class DeckControllerTests
using var doc = JsonDocument.Parse(body);
var decks = doc.RootElement.GetProperty("user_deck_list");
Assert.That(decks.GetArrayLength(), Is.EqualTo(1));
Assert.That(decks[0].GetProperty("name").GetString(), Is.EqualTo("Unlimited Deck"));
Assert.That(decks[0].GetProperty("deck_name").GetString(), Is.EqualTo("Unlimited Deck"));
}
[Test]
@@ -232,7 +232,7 @@ public class DeckControllerTests
Assert.That(decks.GetArrayLength(), Is.EqualTo(2),
"/deck/update should hand back the full refreshed list, saving the client a follow-up.");
var names = Enumerable.Range(0, decks.GetArrayLength())
.Select(i => decks[i].GetProperty("name").GetString())
.Select(i => decks[i].GetProperty("deck_name").GetString())
.ToList();
Assert.That(names, Is.EquivalentTo(new[] { "Existing", "Second" }));
}
@@ -252,7 +252,7 @@ public class DeckControllerTests
var body = await response.Content.ReadAsStringAsync();
using var doc = JsonDocument.Parse(body);
Assert.That(doc.RootElement.GetProperty("user_deck").GetProperty("name").GetString(),
Assert.That(doc.RootElement.GetProperty("user_deck").GetProperty("deck_name").GetString(),
Is.EqualTo("New Name"));
using var scope = factory.Services.CreateScope();

View File

@@ -17,24 +17,23 @@ public class LoadControllerTests
"""{"viewer_id":"0","steam_id":0,"steam_session_ticket":"","carrier":"steam","card_master_hash":""}""";
/// <summary>
/// JSON keys (camelCased C# property names) for fields the client reads unconditionally.
/// These come from the plain-JSON path; the wire-format snake_case keys
/// (<c>user_rank</c>, <c>rotation_card_set_id_list</c>, ...) only apply when the
/// encrypted msgpack pipeline is in play — see <c>EncryptedPipelineTests</c> (Phase 6).
/// Missing any of these is a wire-shape regression in either path.
/// Wire keys (from <c>[Key("...")]</c> / mirrored <c>[JsonPropertyName]</c>) for fields the
/// client reads unconditionally in <c>LoadDetail.ConvertJsonData</c>. These are the names
/// the decompiled client actually looks up — NOT <c>SnakeCaseLower(C# property name)</c>.
/// Missing any of these crashes the client with <c>KeyNotFoundException</c> on /load/index.
/// </summary>
private static readonly string[] RequiredIndexKeys =
{
"user_tutorial", "user_info", "user_currency", "user_items",
"user_rotation_decks", "user_unlimited_decks", "user_my_rotation_decks",
"user_cards", "user_classes", "sleeves", "user_emblems",
"user_degrees", "leader_skins", "my_page_backgrounds",
"user_rank_info", "user_ranked_matches", "daily_login_bonus", "arena_config",
"red_ether_overrides", "maintenance_cards", "arena_infos", "rank_info",
"class_exp", "loading_tip_card_exclusions", "default_settings",
"unlimited_ban_list", "rotation_sets",
"reprinted_cards", "spot_cards", "feature_maintenances",
"special_crystal_infos", "open_battlefield_ids", "loot_box_regulations",
"user_tutorial", "user_info", "user_crystal_count", "user_item_list",
"user_deck_rotation", "user_deck_unlimited", "user_deck_my_rotation",
"user_card_list", "user_class_list", "user_sleeve_list", "user_emblem_list",
"user_degree_list", "user_leader_skin_list", "user_mypage_list",
"user_rank", "user_rank_match_list", "daily_login_bonus", "challenge_config",
"red_ether_overwrite_list", "maintenance_card_list", "rank_info",
"class_exp", "loading_exclusion_card_list", "default_setting",
"unlimited_restricted_base_card_id_list", "rotation_card_set_id_list",
"reprinted_base_card_ids", "spot_cards", "feature_maintenance_list",
"special_crystal_info", "open_battle_field_id_list", "loot_box_regulation",
"gathering_info", "user_config", "deck_format", "card_set_id_for_resource_dl_view"
};
@@ -100,7 +99,7 @@ public class LoadControllerTests
var root = await PostIndexAndReadBody(factory, viewerId);
Assert.That(root.GetProperty("user_rank_info").ValueKind, Is.EqualTo(JsonValueKind.Array));
Assert.That(root.GetProperty("user_rank").ValueKind, Is.EqualTo(JsonValueKind.Array));
}
[Test]
@@ -114,7 +113,7 @@ public class LoadControllerTests
var root = await PostIndexAndReadBody(factory, viewerId);
Assert.That(root.GetProperty("user_rank_info").GetArrayLength(), Is.EqualTo(5));
Assert.That(root.GetProperty("user_rank").GetArrayLength(), Is.EqualTo(5));
}
[Test]
@@ -127,10 +126,26 @@ public class LoadControllerTests
var root = await PostIndexAndReadBody(factory, viewerId);
Assert.That(root.GetProperty("rotation_sets").GetArrayLength(),
Assert.That(root.GetProperty("rotation_card_set_id_list").GetArrayLength(),
Is.GreaterThanOrEqualTo(2));
}
[Test]
public async Task Index_omits_arena_info_when_empty()
{
// ArenaData(JsonData) ctor reads data[0] inside the Keys.Contains("arena_info")
// branch (LoadDetail.cs:261 → ArenaData.cs:48) — an empty array crashes the client
// with ArgumentOutOfRangeException. Field must be absent when there's no arena.
using var factory = new SVSimTestFactory();
long viewerId = await factory.SeedViewerAsync();
var root = await PostIndexAndReadBody(factory, viewerId);
Assert.That(root.TryGetProperty("arena_info", out _), Is.False,
"arena_info must be omitted when empty; the client crashes on []. " +
"If you re-add it, populate at least one entry with a valid format_info.");
}
[Test]
public async Task Index_when_viewer_has_no_decks_returns_empty_format_lists()
{
@@ -141,15 +156,15 @@ public class LoadControllerTests
var root = await PostIndexAndReadBody(factory, viewerId);
foreach (var key in new[] { "user_rotation_decks", "user_unlimited_decks", "user_my_rotation_decks" })
foreach (var key in new[] { "user_deck_rotation", "user_deck_unlimited", "user_deck_my_rotation" })
{
var container = root.GetProperty(key);
Assert.That(container.ValueKind, Is.EqualTo(JsonValueKind.Object),
$"{key} should be the UserFormatDeckInfo object wrapper, not a raw array.");
var inner = container.GetProperty("user_decks");
var inner = container.GetProperty("user_deck_list");
Assert.That(inner.ValueKind, Is.EqualTo(JsonValueKind.Array));
Assert.That(inner.GetArrayLength(), Is.EqualTo(0),
$"{key}.userDecks must be an empty array for a deckless viewer, not null.");
$"{key}.user_deck_list must be an empty array for a deckless viewer, not null.");
}
}
}

View File

@@ -58,9 +58,9 @@ public class PracticeControllerTests
var rotation = doc.RootElement.GetProperty("user_deck_rotation");
var unlimited = doc.RootElement.GetProperty("user_deck_unlimited");
Assert.That(rotation.GetArrayLength(), Is.EqualTo(1));
Assert.That(rotation[0].GetProperty("name").GetString(), Is.EqualTo("Rotation Deck"));
Assert.That(rotation[0].GetProperty("deck_name").GetString(), Is.EqualTo("Rotation Deck"));
Assert.That(unlimited.GetArrayLength(), Is.EqualTo(1));
Assert.That(unlimited[0].GetProperty("name").GetString(), Is.EqualTo("Unlimited Deck"));
Assert.That(unlimited[0].GetProperty("deck_name").GetString(), Is.EqualTo("Unlimited Deck"));
}
[Test]