feat(http): ArenaTwoPickBattleController (do_matching stub + finish)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
gamer147
2026-05-31 11:27:02 -04:00
parent f272690a31
commit 09b8c49743
6 changed files with 207 additions and 0 deletions

View File

@@ -0,0 +1,47 @@
using Microsoft.AspNetCore.Mvc;
using SVSim.EmulatedEntrypoint.Models.Dtos.Requests.ArenaTwoPick;
using SVSim.EmulatedEntrypoint.Models.Dtos.Responses.ArenaTwoPick;
using SVSim.EmulatedEntrypoint.Services;
namespace SVSim.EmulatedEntrypoint.Controllers;
[Route("arena_two_pick_battle")]
public class ArenaTwoPickBattleController : SVSimController
{
private readonly IArenaTwoPickService _svc;
public ArenaTwoPickBattleController(IArenaTwoPickService svc) => _svc = svc;
[HttpPost("do_matching")]
public IActionResult DoMatching([FromBody] DoMatchingRequest req)
{
if (!TryGetViewerId(out _)) return Unauthorized();
return Ok(new DoMatchingResponseDto());
}
[HttpPost("finish")]
public async Task<IActionResult> Finish([FromBody] BattleFinishRequest req)
{
if (!TryGetViewerId(out var vid)) return Unauthorized();
try
{
var result = await _svc.RecordBattleResultAsync(vid, req.BattleResult == 1);
return Ok(new BattleFinishResponseDto
{
BattleResult = result.BattleResult,
GetClassExperience = result.GetClassExperience,
ClassExperience = result.ClassExperience,
ClassLevel = result.ClassLevel,
SpotPointInfo = new SpotPointInfoDto
{
BeforeSpotPoint = result.BeforeSpotPoint,
AddSpotPoint = result.AddSpotPoint,
AfterSpotPoint = result.AfterSpotPoint,
},
});
}
catch (ArenaTwoPickException ex)
{
return BadRequest(new { error_code = ex.ErrorCode });
}
}
}

View File

@@ -0,0 +1,16 @@
using System.Text.Json.Serialization;
using MessagePack;
namespace SVSim.EmulatedEntrypoint.Models.Dtos.Requests.ArenaTwoPick;
[MessagePackObject]
public class BattleFinishRequest
{
[JsonPropertyName("class_id")] [Key("class_id")] public int ClassId { get; set; }
[JsonPropertyName("total_turn")] [Key("total_turn")] public int TotalTurn { get; set; }
[JsonPropertyName("evolve_count")] [Key("evolve_count")] public int EvolveCount { get; set; }
[JsonPropertyName("enemy_evolve_count")] [Key("enemy_evolve_count")] public int EnemyEvolveCount { get; set; }
[JsonPropertyName("battle_result")] [Key("battle_result")] public int BattleResult { get; set; }
[JsonPropertyName("is_retire")] [Key("is_retire")] public int IsRetire { get; set; }
[JsonPropertyName("SDTRB")] [Key("SDTRB")] public int Sdtrb { get; set; }
}

View File

@@ -0,0 +1,16 @@
using System.Text.Json.Serialization;
using MessagePack;
namespace SVSim.EmulatedEntrypoint.Models.Dtos.Requests.ArenaTwoPick;
[MessagePackObject]
public class DoMatchingRequest
{
[JsonPropertyName("card_master_hash")] [Key("card_master_hash")] public string? CardMasterHash { get; set; }
[JsonPropertyName("deck_no")] [Key("deck_no")] public long DeckNo { get; set; }
[JsonPropertyName("need_init")] [Key("need_init")] public int NeedInit { get; set; }
[JsonPropertyName("log")] [Key("log")] public int Log { get; set; }
[JsonPropertyName("excluded_field_id_list")] [Key("excluded_field_id_list")] public List<long> ExcludedFieldIdList { get; set; } = new();
[JsonPropertyName("use_stage_select")] [Key("use_stage_select")] public int UseStageSelect { get; set; }
[JsonPropertyName("is_default_skin")] [Key("is_default_skin")] public int IsDefaultSkin { get; set; }
}

View File

@@ -0,0 +1,74 @@
using System.Text.Json.Serialization;
using MessagePack;
using SVSim.EmulatedEntrypoint.Models.Dtos.Common;
using SVSim.EmulatedEntrypoint.Models.Dtos.Common.ArenaTwoPick;
namespace SVSim.EmulatedEntrypoint.Models.Dtos.Responses.ArenaTwoPick;
[MessagePackObject]
public class BattleFinishResponseDto
{
[JsonPropertyName("class_experience")] [Key("class_experience")]
public int ClassExperience { get; set; }
[JsonPropertyName("get_class_experience")] [JsonConverter(typeof(StringifiedIntConverter))] [Key("get_class_experience")]
public int GetClassExperience { get; set; }
[JsonPropertyName("class_level")] [JsonConverter(typeof(StringifiedIntConverter))] [Key("class_level")]
public int ClassLevel { get; set; }
[JsonPropertyName("battle_result")] [Key("battle_result")]
public int BattleResult { get; set; }
[JsonPropertyName("spot_point_info")] [Key("spot_point_info")]
public SpotPointInfoDto SpotPointInfo { get; set; } = new();
[JsonPropertyName("achieved_info")] [Key("achieved_info")]
public ArenaTwoPickAchievedInfoDto AchievedInfo { get; set; } = new();
[JsonPropertyName("result_decision")] [Key("result_decision")]
public int ResultDecision { get; set; } = 1;
[JsonPropertyName("reward_list")] [Key("reward_list")]
public List<RewardEntryDto> RewardList { get; set; } = new();
[JsonPropertyName("gathering_notification")] [Key("gathering_notification")]
public GatheringNotificationDto GatheringNotification { get; set; } = new();
[JsonPropertyName("battle_dialog_list")] [Key("battle_dialog_list")]
public List<object> BattleDialogList { get; set; } = new();
}
[MessagePackObject]
public class SpotPointInfoDto
{
[JsonPropertyName("before_spot_point")] [Key("before_spot_point")] public int BeforeSpotPoint { get; set; }
[JsonPropertyName("add_spot_point")] [JsonConverter(typeof(StringifiedIntConverter))] [Key("add_spot_point")] public int AddSpotPoint { get; set; }
[JsonPropertyName("after_spot_point")] [Key("after_spot_point")] public int AfterSpotPoint { get; set; }
}
[MessagePackObject]
public class GatheringNotificationDto
{
[JsonPropertyName("matching_established_message")] [Key("matching_established_message")]
public string MatchingEstablishedMessage { get; set; } = "";
}
[MessagePackObject]
public class ArenaTwoPickAchievedInfoDto
{
[JsonPropertyName("achieved_achievement_list")] [Key("achieved_achievement_list")]
public List<object> AchievedAchievementList { get; set; } = new();
[JsonPropertyName("achieved_mission_list")] [Key("achieved_mission_list")]
public List<object> AchievedMissionList { get; set; } = new();
[JsonPropertyName("achieved_mission_reward_list")] [Key("achieved_mission_reward_list")]
public List<object> AchievedMissionRewardList { get; set; } = new();
[JsonPropertyName("grand_master_reward_list")] [Key("grand_master_reward_list")]
public List<object> GrandMasterRewardList { get; set; } = new();
[JsonPropertyName("mission_start_data")] [Key("mission_start_data")]
public List<object> MissionStartData { get; set; } = new();
}

View File

@@ -0,0 +1,30 @@
using System.Text.Json.Serialization;
using MessagePack;
using SVSim.EmulatedEntrypoint.Models.Dtos.Common;
namespace SVSim.EmulatedEntrypoint.Models.Dtos.Responses.ArenaTwoPick;
[MessagePackObject]
public class DoMatchingResponseDto
{
[JsonPropertyName("timeout_period")] [JsonConverter(typeof(StringifiedIntConverter))] [Key("timeout_period")]
public int TimeoutPeriod { get; set; } = 50;
[JsonPropertyName("retry_period")] [JsonConverter(typeof(StringifiedIntConverter))] [Key("retry_period")]
public int RetryPeriod { get; set; } = 3;
[JsonPropertyName("node_server_url")] [Key("node_server_url")]
public string NodeServerUrl { get; set; } = "";
[JsonPropertyName("room_param")] [Key("room_param")]
public string RoomParam { get; set; } = "";
[JsonPropertyName("matching_state")] [Key("matching_state")]
public int MatchingState { get; set; } = 3002;
[JsonPropertyName("mission_parameter")] [Key("mission_parameter")]
public Dictionary<string, string> MissionParameter { get; set; } = new()
{
["follower_play_count_for_mission"] = "{me.game_play_cards_other_self.unit.count}",
};
}

View File

@@ -0,0 +1,24 @@
using System.Net;
using System.Net.Http.Json;
using SVSim.UnitTests.Infrastructure;
namespace SVSim.UnitTests.Controllers;
public class ArenaTwoPickBattleControllerTests
{
[Test]
public async Task DoMatching_returns_perpetual_searching_with_empty_node_url()
{
using var factory = new SVSimTestFactory();
var viewerId = await factory.SeedViewerAsync();
using var client = factory.CreateAuthenticatedClient(viewerId);
var req = new { deck_no = 1L, need_init = 1, log = 1, excluded_field_id_list = new long[] { }, use_stage_select = 1, is_default_skin = 0 };
var resp = await client.PostAsync("/arena_two_pick_battle/do_matching", JsonContent.Create(req));
Assert.That(resp.StatusCode, Is.EqualTo(HttpStatusCode.OK));
var body = await resp.Content.ReadAsStringAsync();
StringAssert.Contains("\"matching_state\":3002", body);
StringAssert.Contains("\"node_server_url\":\"\"", body);
StringAssert.DoesNotContain("\"battle_id\"", body);
}
}