using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using DorkNet.Server.Auth; using DorkNet.Server.Data; using DorkNet.Server.Data.Entities; using System.Text.Json.Serialization; namespace DorkNet.Server.Controllers.API.Settings.V2; /// /// api.rec.net/api/settings/v2 — player settings download / set / remove. /// URL patterns (verified by disassembling RecNet.Settings$$DowloadLocalPlayerSettings /// at RVA 0xAF55B0 and RecNet.Settings$$StoreLocalPlayerSetting at RVA 0xAF5650): /// /// GET api/settings/v2/ — returns List<{Key, Value}> /// POST api/settings/v2/set — body { Key, Value } (set or update one) /// POST api/settings/v2/remove — body { Key } (delete one) /// /// The CLIENT side parses the GET response with Util.DeserializeList<Setting> /// and reads each entry's "Key" and "Value" fields (verified by string literal /// references in the deserializer body — both are PascalCase). /// /// Returning a Dictionary<string,string> here serializes as "{}" /// when empty, which the client casts to a List and dies with /// InvalidCastException: Unable to cast object of type 'Dictionary`2' to /// type 'List`1'. Always return a real List. /// [ApiController] [Route("api/[controller]/v2")] [Authorize] public class SettingsController(DorkNetDbContext db) : ControllerBase { private long CurrentPlayerId => this.RequireCurrentPlayerId(); [HttpGet] [HttpGet("get")] public async Task GetSettings() { var settings = await db.PlayerSettings .Where(s => s.PlayerId == CurrentPlayerId) .Select(s => new SettingDto { Key = s.Key, Value = s.Value }) .ToListAsync(); return Ok(settings); } [HttpPost("set")] public async Task SetSetting([FromBody] SetSettingRequest req) { var existing = await db.PlayerSettings .FirstOrDefaultAsync(s => s.PlayerId == CurrentPlayerId && s.Key == req.Key); if (existing is null) { db.PlayerSettings.Add(new PlayerSettingEntity { PlayerId = CurrentPlayerId, Key = req.Key, Value = req.Value, }); } else { existing.Value = req.Value; } await db.SaveChangesAsync(); return Ok(new SettingDto { Key = req.Key, Value = req.Value }); } [HttpPost("remove")] public async Task RemoveSetting([FromBody] SetSettingRequest req) { var existing = await db.PlayerSettings .FirstOrDefaultAsync(s => s.PlayerId == CurrentPlayerId && s.Key == req.Key); if (existing is not null) { db.PlayerSettings.Remove(existing); await db.SaveChangesAsync(); } return Ok(); } } public class SettingDto { [JsonPropertyName("Key")] public string Key { get; set; } = string.Empty; [JsonPropertyName("Value")] public string Value { get; set; } = string.Empty; } public class SetSettingRequest { [JsonPropertyName("Key")] public string Key { get; set; } = string.Empty; [JsonPropertyName("Value")] public string Value { get; set; } = string.Empty; }