Adding player sensing
Deploy Promiscuity Auth API / deploy (push) Successful in 47s
Deploy Promiscuity Character API / deploy (push) Successful in 59s
Deploy Promiscuity Inventory API / deploy (push) Successful in 47s
Deploy Promiscuity Locations API / deploy (push) Successful in 47s
k8s smoke test / test (push) Successful in 9s

This commit is contained in:
2026-03-23 18:39:08 -05:00
parent c596b760cf
commit bca8e3374a
6 changed files with 247 additions and 13 deletions
@@ -13,6 +13,7 @@ namespace CharacterApi.Controllers;
[Route("api/[controller]")]
public class CharactersController : ControllerBase
{
private static readonly TimeSpan PresenceTimeout = TimeSpan.FromSeconds(45);
private readonly CharacterStore _characters;
private readonly IHttpClientFactory _httpClientFactory;
private readonly IConfiguration _configuration;
@@ -43,6 +44,7 @@ public class CharactersController : ControllerBase
Name = req.Name.Trim(),
Coord = new Coord { X = 0, Y = 0 },
VisionRadius = 3,
LastSeenUtc = DateTime.UtcNow,
CreatedUtc = DateTime.UtcNow
};
@@ -89,6 +91,8 @@ public class CharactersController : ControllerBase
return Forbid();
}
await _characters.TouchAsync(id);
_logger.LogInformation(
"Visible locations requested for character {CharacterId} at ({X},{Y}) radius {VisionRadius} by user {UserId}",
character.Id,
@@ -164,6 +168,53 @@ public class CharactersController : ControllerBase
}
}
[HttpGet("{id}/visible-characters")]
[Authorize(Roles = "USER,SUPER")]
public async Task<IActionResult> VisibleCharacters(string id)
{
var userId = User.FindFirstValue(ClaimTypes.NameIdentifier);
if (string.IsNullOrWhiteSpace(userId))
return Unauthorized();
var allowAnyOwner = User.IsInRole("SUPER");
var character = await _characters.GetByIdAsync(id);
if (character is null)
return NotFound();
if (!allowAnyOwner && character.OwnerUserId != userId)
return Forbid();
await _characters.TouchAsync(id);
var onlineSinceUtc = DateTime.UtcNow.Subtract(PresenceTimeout);
var visibleCharacters = await _characters.GetVisibleOthersAsync(
id,
character.Coord.X,
character.Coord.Y,
character.VisionRadius > 0 ? character.VisionRadius : 3,
onlineSinceUtc);
return Ok(visibleCharacters);
}
[HttpPost("{id}/heartbeat")]
[Authorize(Roles = "USER,SUPER")]
public async Task<IActionResult> Heartbeat(string id)
{
var userId = User.FindFirstValue(ClaimTypes.NameIdentifier);
if (string.IsNullOrWhiteSpace(userId))
return Unauthorized();
var allowAnyOwner = User.IsInRole("SUPER");
var character = await _characters.GetByIdAsync(id);
if (character is null)
return NotFound();
if (!allowAnyOwner && character.OwnerUserId != userId)
return Forbid();
await _characters.TouchAsync(id);
return Ok(new { lastSeenUtc = DateTime.UtcNow });
}
[HttpPut("{id}/coord")]
[Authorize(Roles = "USER,SUPER")]
public async Task<IActionResult> UpdateCoord(string id, [FromBody] UpdateCharacterCoordRequest req)