This commit is contained in:
hz
2025-05-08 09:29:20 -05:00
parent 4f67e2b56f
commit c0a94f26d6
31 changed files with 1181 additions and 0 deletions
+282
View File
@@ -0,0 +1,282 @@
// Controllers/PlayerController.cs
using GameAuthApi.Models;
using GameAuthApi.Services;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
namespace GameAuthApi.Controllers;
[ApiController]
[Route("api/[controller]")]
public class PlayerController : ControllerBase
{
private readonly PlayerService _playerService;
private readonly LocationService _locationService;
private readonly SpawnableService _spawnableService;
private readonly ItemService _itemService;
public PlayerController(PlayerService playerService, LocationService locationService, SpawnableService spawnableService, ItemService itemService)
{
_playerService = playerService;
_locationService = locationService;
_spawnableService = spawnableService;
_itemService = itemService;
}
[HttpPost]
[Authorize(Roles = "USER,SUPER")]
public async Task<IActionResult> Create([FromBody] CreatePlayerRequest req)
{
var userId = User.FindFirstValue(ClaimTypes.NameIdentifier);
if (string.IsNullOrEmpty(userId))
return Unauthorized("User ID not found in token.");
var existing = await _playerService.GetByUserIdAsync(userId);
if (existing != null)
return BadRequest("Player already exists for this user.");
Location spawnLocation = null;
if (!string.IsNullOrWhiteSpace(req.LocationId))
{
spawnLocation = await _locationService.GetByIdAsync(req.LocationId);
if (spawnLocation == null)
return BadRequest("Specified location does not exist.");
}
else
{
spawnLocation = await _locationService.GetSpawnLocationAsync();
// If not found, spawnLocation remains null
}
// create the inventory location
var inventoryLocation = new Location
{
LocationType = "Inventory",
X = null,
Y = null,
Z = null,
N = null,
NE = null,
E = null,
SE = null,
S = null,
SW = null,
W = null,
NW = null,
Players = new List<string>() // optional
};
await _locationService.CreateAsync(inventoryLocation);
var player = new Player
{
UserId = userId,
Name = req.Name,
LocationId = spawnLocation?.Id,
InventoryLocationId = inventoryLocation.Id,
Climbing = 3
};
await _playerService.CreateAsync(player);
if (spawnLocation != null)
{
await _locationService.AddPlayerToLocationAsync(spawnLocation.Id, player.Id);
}
return Ok(player);
}
[HttpDelete]
[Authorize(Roles = "USER,SUPER")]
public async Task<IActionResult> Delete()
{
var userId = User.FindFirstValue(ClaimTypes.NameIdentifier);
var role = User.FindFirstValue(ClaimTypes.Role);
var player = await _playerService.GetByUserIdAsync(userId);
if (player == null)
return NotFound("No player found for this user.");
// Remove from current location if set
if (!string.IsNullOrEmpty(player.LocationId))
{
await _locationService.RemovePlayerFromLocationAsync(player.LocationId, player.Id);
}
await _playerService.DeleteAsync(player.Id);
return Ok($"Player '{player.Name}' deleted.");
}
[HttpPost("teleport")]
[Authorize(Roles = "SUPER")]
public async Task<IActionResult> AdminTeleport([FromBody] TeleportRequest req)
{
var player = await _playerService.GetByIdAsync(req.PlayerId);
if (player == null)
return NotFound("Player not found.");
var newLocation = await _locationService.GetByIdAsync(req.LocationId);
if (newLocation == null)
return BadRequest("Target location does not exist.");
if (!string.IsNullOrEmpty(player.LocationId))
{
await _locationService.RemovePlayerFromLocationAsync(player.LocationId, player.Id);
}
player.LocationId = newLocation.Id;
await _playerService.UpdateAsync(player);
await _locationService.AddPlayerToLocationAsync(newLocation.Id, player.Id);
return Ok($"Player '{player.Name}' teleported to '{newLocation.X}, {newLocation.Y}'.");
}
[HttpPost("move")]
[Authorize(Roles = "USER,SUPER")]
public async Task<IActionResult> Move([FromBody] MoveRequest req)
{
var userId = User.FindFirstValue(ClaimTypes.NameIdentifier);
var player = await _playerService.GetByUserIdAsync(userId);
if (player == null)
return NotFound("Player not found.");
if (string.IsNullOrWhiteSpace(player.LocationId))
return BadRequest("Player is not currently in a location.");
var currentLocation = await _locationService.GetByIdAsync(player.LocationId);
if (currentLocation == null)
return BadRequest("Current location not found.");
var direction = req.Direction.ToUpper();
var directionMap = new Dictionary<string, (int dx, int dy, string reverse)>
{
{ "N", (0, 1, "S") }, { "NE", (1, 1, "SW") }, { "E", (1, 0, "W") }, { "SE", (1, -1, "NW") },
{ "S", (0, -1, "N") }, { "SW", (-1, -1, "NE") }, { "W", (-1, 0, "E") }, { "NW", (-1, 1, "SE") }
};
if (!directionMap.ContainsKey(direction))
return BadRequest("Invalid direction. Use N, NE, E, SE, S, SW, W, or NW.");
var (dx, dy, reverseDir) = directionMap[direction];
var targetId = typeof(Location).GetProperty(direction)?.GetValue(currentLocation)?.ToString();
Location targetLocation;
if (!string.IsNullOrWhiteSpace(targetId))
{
targetLocation = await _locationService.GetByIdAsync(targetId);
if (targetLocation == null)
return BadRequest("Linked location ID is invalid.");
var z1 = currentLocation.Z ?? 0;
var z2 = targetLocation.Z ?? 0;
var zDiff = Math.Abs(z1 - z2);
if (zDiff > player.Climbing)
{
return BadRequest($"Cannot move {req.Direction.ToUpper()}: elevation difference ({zDiff}) exceeds your climbing ability ({player.Climbing}).");
}
}
else
{
// Generate new location
var newX = currentLocation.X + dx;
var newY = currentLocation.Y + dy;
var random = new Random();
var newZ = currentLocation.Z + random.Next(-1, 2); // -1, 0, or +1
string itemId = null;
var spawnables = await _spawnableService.GetAllAsync();
if (spawnables.Any())
{
var rng = new Random();
var roll = rng.Next(0, 100); // 0–99
foreach (var s in spawnables.OrderBy(s => s.SpawnRate))
{
if (roll < s.SpawnRate)
{
var tempItem = new Item
{
Name = s.Name,
LocationId = null
};
await _itemService.CreateAsync(tempItem);
itemId = tempItem.Id;
break;
}
}
}
targetLocation = new Location
{
LocationType = "World",
X = newX,
Y = newY,
Z = newZ,
Content = itemId != null ? [itemId] : []
};
await _locationService.CreateAsync(targetLocation);
if (itemId != null)
{
var createdItem = await _itemService.GetByIdAsync(itemId);
createdItem.LocationId = targetLocation.Id;
await _itemService.UpdateAsync(createdItem);
}
// Link current → new
typeof(Location).GetProperty(direction)?.SetValue(currentLocation, targetLocation.Id);
// Link new → current
typeof(Location).GetProperty(reverseDir)?.SetValue(targetLocation, currentLocation.Id);
await _locationService.UpdateAsync(currentLocation);
await _locationService.UpdateAsync(targetLocation);
// Link additional neighbors
foreach (var entry in directionMap)
{
var dir = entry.Key;
var (nx, ny, rev) = entry.Value;
var neighbor = await _locationService.GetByCoordinatesAsync(
(targetLocation.X ?? 0) + nx,
(targetLocation.Y ?? 0) + ny,
targetLocation.Z ?? 0);
if (neighbor != null)
{
typeof(Location).GetProperty(dir)?.SetValue(targetLocation, neighbor.Id);
typeof(Location).GetProperty(rev)?.SetValue(neighbor, targetLocation.Id);
await _locationService.UpdateAsync(neighbor);
}
}
await _locationService.UpdateAsync(targetLocation);
}
// Move the player
await _locationService.RemovePlayerFromLocationAsync(currentLocation.Id, player.Id);
await _locationService.AddPlayerToLocationAsync(targetLocation.Id, player.Id);
player.LocationId = targetLocation.Id;
await _playerService.UpdateAsync(player);
return Ok($"Player '{player.Name}' moved {direction} to '{targetLocation.X}, {targetLocation.Y}'.");
}
private static readonly Dictionary<string, (int dx, int dy, string reverse)> DirectionData = new()
{
{ "N", (0, 1, "S") }, { "NE", (1, 1, "SW") }, { "E", (1, 0, "W") }, { "SE", (1, -1, "NW") },
{ "S", (0, -1, "N") }, { "SW", (-1, -1, "NE") }, { "W", (-1, 0, "E") }, { "NW", (-1, 1, "SE") }
};
}