Commit 0
This commit is contained in:
@@ -0,0 +1,139 @@
|
|||||||
|
using GameAuthApi.Models;
|
||||||
|
using GameAuthApi.Services;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
using Microsoft.IdentityModel.Tokens;
|
||||||
|
using System;
|
||||||
|
using System.IdentityModel.Tokens.Jwt;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Security.Claims;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace GameAuthApi.Controllers;
|
||||||
|
|
||||||
|
[ApiController]
|
||||||
|
[Route("api/[controller]")]
|
||||||
|
public class AuthController : ControllerBase
|
||||||
|
{
|
||||||
|
private readonly UserService _userService;
|
||||||
|
private readonly IConfiguration _config;
|
||||||
|
private readonly BlacklistService _blacklistService;
|
||||||
|
|
||||||
|
public AuthController(UserService userService, IConfiguration config, BlacklistService blacklistService)
|
||||||
|
{
|
||||||
|
_userService = userService;
|
||||||
|
_config = config;
|
||||||
|
_blacklistService = blacklistService;
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost("register")]
|
||||||
|
public async Task<IActionResult> Register([FromBody] RegisterRequest credentials)
|
||||||
|
{
|
||||||
|
if (await _userService.GetByUsernameAsync(credentials.Username) != null)
|
||||||
|
return BadRequest("User already exists");
|
||||||
|
|
||||||
|
var hash = BCrypt.Net.BCrypt.HashPassword(credentials.Password);
|
||||||
|
|
||||||
|
var user = new User
|
||||||
|
{
|
||||||
|
Username = credentials.Username,
|
||||||
|
PasswordHash = hash,
|
||||||
|
Role = "USER",
|
||||||
|
Email = credentials.Email
|
||||||
|
};
|
||||||
|
|
||||||
|
await _userService.CreateAsync(user);
|
||||||
|
return Ok("User created");
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost("login")]
|
||||||
|
public async Task<IActionResult> Login([FromBody] LoginRequest credentials)
|
||||||
|
{
|
||||||
|
var user = await _userService.GetByUsernameAsync(credentials.Username);
|
||||||
|
if (user == null || !BCrypt.Net.BCrypt.Verify(credentials.Password, user.PasswordHash))
|
||||||
|
return Unauthorized();
|
||||||
|
|
||||||
|
var accessToken = GenerateJwtToken(user);
|
||||||
|
var refreshToken = Guid.NewGuid().ToString();
|
||||||
|
var refreshExpiry = DateTime.UtcNow.AddDays(7);
|
||||||
|
|
||||||
|
user.RefreshToken = refreshToken;
|
||||||
|
user.RefreshTokenExpiry = refreshExpiry;
|
||||||
|
await _userService.UpdateAsync(user);
|
||||||
|
|
||||||
|
return Ok(new { accessToken, refreshToken });
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost("refresh")]
|
||||||
|
public async Task<IActionResult> Refresh([FromBody] RefreshRequest req)
|
||||||
|
{
|
||||||
|
var user = await _userService.GetByUsernameAsync(req.Username);
|
||||||
|
if (user == null || user.RefreshToken != req.RefreshToken || user.RefreshTokenExpiry < DateTime.UtcNow)
|
||||||
|
return Unauthorized("Invalid or expired refresh token");
|
||||||
|
|
||||||
|
var newAccessToken = GenerateJwtToken(user);
|
||||||
|
return Ok(new { accessToken = newAccessToken });
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost("logout")]
|
||||||
|
[Authorize(Roles = "USER,SUPER")]
|
||||||
|
public async Task<IActionResult> Logout()
|
||||||
|
{
|
||||||
|
var token = HttpContext.Request.Headers["Authorization"].FirstOrDefault()?.Replace("Bearer ", "");
|
||||||
|
if (string.IsNullOrWhiteSpace(token))
|
||||||
|
return BadRequest("Token missing");
|
||||||
|
|
||||||
|
var jwtToken = new JwtSecurityTokenHandler().ReadToken(token) as JwtSecurityToken;
|
||||||
|
var expiry = jwtToken.ValidTo;
|
||||||
|
|
||||||
|
await _blacklistService.AddToBlacklistAsync(token, expiry);
|
||||||
|
return Ok("Token blacklisted, user logged out.");
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost("role")]
|
||||||
|
[Authorize(Roles = "SUPER")]
|
||||||
|
public async Task<IActionResult> ChangeUserRole([FromBody] ChangeRoleRequest request)
|
||||||
|
{
|
||||||
|
if (request.NewRole != "USER" && request.NewRole != "SUPER")
|
||||||
|
return BadRequest("Role must be 'USER' or 'SUPER'");
|
||||||
|
|
||||||
|
var user = await _userService.GetByUsernameAsync(request.Username);
|
||||||
|
if (user == null)
|
||||||
|
return NotFound("User not found");
|
||||||
|
|
||||||
|
user.Role = request.NewRole;
|
||||||
|
await _userService.UpdateAsync(user);
|
||||||
|
|
||||||
|
return Ok($"{request.Username}'s role updated to {request.NewRole}");
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GenerateJwtToken(User user)
|
||||||
|
{
|
||||||
|
var key = Encoding.UTF8.GetBytes(_config["Jwt:Key"]);
|
||||||
|
var creds = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256);
|
||||||
|
|
||||||
|
var claims = new[]
|
||||||
|
{
|
||||||
|
new Claim(ClaimTypes.Name, user.Username),
|
||||||
|
new Claim(ClaimTypes.NameIdentifier, user.Id),
|
||||||
|
new Claim(ClaimTypes.Role, user.Role)
|
||||||
|
};
|
||||||
|
|
||||||
|
var token = new JwtSecurityToken(
|
||||||
|
_config["Jwt:Issuer"],
|
||||||
|
_config["Jwt:Issuer"],
|
||||||
|
claims,
|
||||||
|
expires: DateTime.UtcNow.AddMinutes(15),
|
||||||
|
signingCredentials: creds);
|
||||||
|
|
||||||
|
return new JwtSecurityTokenHandler().WriteToken(token);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class RefreshRequest
|
||||||
|
{
|
||||||
|
public string Username { get; set; }
|
||||||
|
public string RefreshToken { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
using System.Threading.Tasks;
|
||||||
|
using GameAuthApi.Models;
|
||||||
|
using GameAuthApi.Services;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
|
namespace GameAuthApi.Controllers;
|
||||||
|
|
||||||
|
[ApiController]
|
||||||
|
[Route("api/[controller]")]
|
||||||
|
public class ItemController : ControllerBase
|
||||||
|
{
|
||||||
|
private readonly ItemService _itemService;
|
||||||
|
private readonly LocationService _locationService;
|
||||||
|
|
||||||
|
public ItemController(ItemService itemService, LocationService locationService)
|
||||||
|
{
|
||||||
|
_itemService = itemService;
|
||||||
|
_locationService = locationService;
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost]
|
||||||
|
[Authorize(Roles = "SUPER")]
|
||||||
|
public async Task<IActionResult> Create([FromBody] CreateItemRequest req)
|
||||||
|
{
|
||||||
|
var location = await _locationService.GetByIdAsync(req.LocationId);
|
||||||
|
if (location == null)
|
||||||
|
return BadRequest("Invalid location ID.");
|
||||||
|
|
||||||
|
var item = new Item
|
||||||
|
{
|
||||||
|
Name = req.Name,
|
||||||
|
LocationId = req.LocationId
|
||||||
|
};
|
||||||
|
|
||||||
|
await _itemService.CreateAsync(item);
|
||||||
|
return Ok(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using GameAuthApi.Models;
|
||||||
|
using GameAuthApi.Services;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
|
namespace GameAuthApi.Controllers;
|
||||||
|
|
||||||
|
[ApiController]
|
||||||
|
[Route("api/[controller]")]
|
||||||
|
public class LocationController : ControllerBase
|
||||||
|
{
|
||||||
|
private readonly LocationService _locationService;
|
||||||
|
private readonly PlayerService _playerService;
|
||||||
|
|
||||||
|
public LocationController(LocationService locationService, PlayerService playerService)
|
||||||
|
{
|
||||||
|
_locationService = locationService;
|
||||||
|
_playerService = playerService;
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost]
|
||||||
|
[Authorize(Roles = "SUPER")]
|
||||||
|
public async Task<IActionResult> Create([FromBody] CreateLocationRequest req)
|
||||||
|
{
|
||||||
|
var newLoc = new Location
|
||||||
|
{
|
||||||
|
X = req.X,
|
||||||
|
Y = req.Y,
|
||||||
|
Z = req.Z,
|
||||||
|
N = req.N,
|
||||||
|
NE = req.NE,
|
||||||
|
E = req.E,
|
||||||
|
SE = req.SE,
|
||||||
|
S = req.S,
|
||||||
|
SW = req.SW,
|
||||||
|
W = req.W,
|
||||||
|
NW = req.NW
|
||||||
|
};
|
||||||
|
|
||||||
|
await _locationService.CreateAsync(newLoc);
|
||||||
|
|
||||||
|
return Ok(newLoc);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpDelete("{id}")]
|
||||||
|
[Authorize(Roles = "SUPER")]
|
||||||
|
public async Task<IActionResult> Delete(string id)
|
||||||
|
{
|
||||||
|
var location = await _locationService.GetByIdAsync(id);
|
||||||
|
if (location == null)
|
||||||
|
return NotFound("Location not found.");
|
||||||
|
|
||||||
|
// Null out all players at this location
|
||||||
|
var affectedPlayers = await _playerService.GetByLocationIdAsync(id);
|
||||||
|
foreach (var player in affectedPlayers)
|
||||||
|
{
|
||||||
|
player.LocationId = null;
|
||||||
|
await _playerService.UpdateAsync(player);
|
||||||
|
}
|
||||||
|
|
||||||
|
await _locationService.DeleteAsync(id);
|
||||||
|
return Ok($"Location deleted and {affectedPlayers.Count} player(s) unlinked.");
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("{id}")]
|
||||||
|
[Authorize(Roles = "USER")]
|
||||||
|
public async Task<IActionResult> GetById(string id)
|
||||||
|
{
|
||||||
|
var location = await _locationService.GetByIdAsync(id);
|
||||||
|
if (location == null)
|
||||||
|
return NotFound("Location not found");
|
||||||
|
|
||||||
|
return Ok(location);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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") }
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
using System.Threading.Tasks;
|
||||||
|
using GameAuthApi.Models;
|
||||||
|
using GameAuthApi.Services;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
|
namespace GameAuthApi.Controllers;
|
||||||
|
|
||||||
|
[ApiController]
|
||||||
|
[Route("api/[controller]")]
|
||||||
|
public class SpawnableController : ControllerBase
|
||||||
|
{
|
||||||
|
private readonly SpawnableService _spawnableService;
|
||||||
|
|
||||||
|
public SpawnableController(SpawnableService spawnableService)
|
||||||
|
{
|
||||||
|
_spawnableService = spawnableService;
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost]
|
||||||
|
[Authorize(Roles = "SUPER")]
|
||||||
|
public async Task<IActionResult> Create([FromBody] CreateSpawnableRequest req)
|
||||||
|
{
|
||||||
|
var spawnable = new Spawnable
|
||||||
|
{
|
||||||
|
Name = req.Name.ToLower(),
|
||||||
|
SpawnRate = req.SpawnRate
|
||||||
|
};
|
||||||
|
|
||||||
|
await _spawnableService.CreateAsync(spawnable);
|
||||||
|
return Ok(spawnable);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet]
|
||||||
|
[Authorize(Roles = "SUPER")]
|
||||||
|
public async Task<IActionResult> GetAll()
|
||||||
|
{
|
||||||
|
var all = await _spawnableService.GetAllAsync();
|
||||||
|
return Ok(all);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="MongoDB.Driver" Version="2.21.0" />
|
||||||
|
<PackageReference Include="BCrypt.Net-Next" Version="4.0.2" />
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.0" />
|
||||||
|
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
|
# Visual Studio Version 17
|
||||||
|
VisualStudioVersion = 17.5.2.0
|
||||||
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GameAuthApi", "GameAuthApi.csproj", "{349B73A5-7632-5ADF-4645-BB2EF73FA948}"
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
Release|Any CPU = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{349B73A5-7632-5ADF-4645-BB2EF73FA948}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{349B73A5-7632-5ADF-4645-BB2EF73FA948}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{349B73A5-7632-5ADF-4645-BB2EF73FA948}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{349B73A5-7632-5ADF-4645-BB2EF73FA948}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
|
HideSolutionNode = FALSE
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
|
SolutionGuid = {7EFA1A51-A917-4BB3-9C99-E90800825E9F}
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using GameAuthApi.Services;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
|
||||||
|
namespace GameAuthApi.Middleware;
|
||||||
|
|
||||||
|
public class TokenBlacklistMiddleware
|
||||||
|
{
|
||||||
|
private readonly RequestDelegate _next;
|
||||||
|
|
||||||
|
public TokenBlacklistMiddleware(RequestDelegate next)
|
||||||
|
{
|
||||||
|
_next = next;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task Invoke(HttpContext context, BlacklistService blacklistService)
|
||||||
|
{
|
||||||
|
var token = context.Request.Headers["Authorization"].FirstOrDefault()?.Replace("Bearer ", "");
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(token))
|
||||||
|
{
|
||||||
|
if (await blacklistService.IsTokenBlacklistedAsync(token))
|
||||||
|
{
|
||||||
|
context.Response.StatusCode = 401;
|
||||||
|
await context.Response.WriteAsync("Token has been revoked");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await _next(context);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
using System;
|
||||||
|
using MongoDB.Bson;
|
||||||
|
using MongoDB.Bson.Serialization.Attributes;
|
||||||
|
|
||||||
|
namespace GameAuthApi.Models;
|
||||||
|
|
||||||
|
public class BlacklistedToken
|
||||||
|
{
|
||||||
|
[BsonId]
|
||||||
|
[BsonRepresentation(BsonType.ObjectId)]
|
||||||
|
public string Id { get; set; }
|
||||||
|
public string Token { get; set; }
|
||||||
|
public DateTime Expiry { get; set; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
namespace GameAuthApi.Models;
|
||||||
|
|
||||||
|
public class ChangeRoleRequest
|
||||||
|
{
|
||||||
|
public string Username { get; set; }
|
||||||
|
public string NewRole { get; set; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
namespace GameAuthApi.Models;
|
||||||
|
|
||||||
|
public class CreateItemRequest
|
||||||
|
{
|
||||||
|
public string LocationId { get; set; }
|
||||||
|
|
||||||
|
public string Name { get; set; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
namespace GameAuthApi.Models;
|
||||||
|
|
||||||
|
public class CreateLocationRequest
|
||||||
|
{
|
||||||
|
public int X { get; set; }
|
||||||
|
public int Y { get; set; }
|
||||||
|
public int Z { get; set; }
|
||||||
|
|
||||||
|
public string N { get; set; }
|
||||||
|
public string NE { get; set; }
|
||||||
|
public string E { get; set; }
|
||||||
|
public string SE { get; set; }
|
||||||
|
public string S { get; set; }
|
||||||
|
public string SW { get; set; }
|
||||||
|
public string W { get; set; }
|
||||||
|
public string NW { get; set; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
// Models/CreatePlayerRequest.cs
|
||||||
|
namespace GameAuthApi.Models;
|
||||||
|
|
||||||
|
public class CreatePlayerRequest
|
||||||
|
{
|
||||||
|
public string Name { get; set; }
|
||||||
|
public string LocationId { get; set; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
namespace GameAuthApi.Models;
|
||||||
|
|
||||||
|
public class CreateSpawnableRequest
|
||||||
|
{
|
||||||
|
public string Name { get; set; }
|
||||||
|
public int SpawnRate { get; set; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
namespace GameAuthApi.Models;
|
||||||
|
|
||||||
|
public class LoginRequest
|
||||||
|
{
|
||||||
|
public string Username { get; set; }
|
||||||
|
public string Password { get; set; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
namespace GameAuthApi.Models;
|
||||||
|
|
||||||
|
public class MoveRequest
|
||||||
|
{
|
||||||
|
public string Direction { get; set; } // N, NE, E, SE, S, SW, W, NW
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
namespace GameAuthApi.Models;
|
||||||
|
|
||||||
|
public class RegisterRequest
|
||||||
|
{
|
||||||
|
public string Username { get; set; }
|
||||||
|
public string Password { get; set; }
|
||||||
|
public string Email { get; set; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
namespace GameAuthApi.Models;
|
||||||
|
|
||||||
|
public class TeleportRequest
|
||||||
|
{
|
||||||
|
public string PlayerId { get; set; }
|
||||||
|
public string LocationId { get; set; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
using MongoDB.Bson;
|
||||||
|
using MongoDB.Bson.Serialization.Attributes;
|
||||||
|
|
||||||
|
namespace GameAuthApi.Models;
|
||||||
|
|
||||||
|
public class Item
|
||||||
|
{
|
||||||
|
[BsonId]
|
||||||
|
[BsonRepresentation(BsonType.ObjectId)]
|
||||||
|
public string Id { get; set; }
|
||||||
|
|
||||||
|
[BsonRepresentation(BsonType.ObjectId)]
|
||||||
|
public string LocationId { get; set; }
|
||||||
|
|
||||||
|
public string Name { get; set; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using MongoDB.Bson;
|
||||||
|
using MongoDB.Bson.Serialization.Attributes;
|
||||||
|
|
||||||
|
namespace GameAuthApi.Models;
|
||||||
|
|
||||||
|
public class Location
|
||||||
|
{
|
||||||
|
[BsonId]
|
||||||
|
[BsonRepresentation(BsonType.ObjectId)]
|
||||||
|
public string Id { get; set; }
|
||||||
|
|
||||||
|
public string LocationType { get; set; } = "World";
|
||||||
|
|
||||||
|
public int? X { get; set; }
|
||||||
|
public int? Y { get; set; }
|
||||||
|
public int? Z { get; set; }
|
||||||
|
|
||||||
|
[BsonRepresentation(BsonType.ObjectId)]
|
||||||
|
public string N { get; set; }
|
||||||
|
[BsonRepresentation(BsonType.ObjectId)]
|
||||||
|
public string NE { get; set; }
|
||||||
|
[BsonRepresentation(BsonType.ObjectId)]
|
||||||
|
public string E { get; set; }
|
||||||
|
[BsonRepresentation(BsonType.ObjectId)]
|
||||||
|
public string SE { get; set; }
|
||||||
|
[BsonRepresentation(BsonType.ObjectId)]
|
||||||
|
public string S { get; set; }
|
||||||
|
[BsonRepresentation(BsonType.ObjectId)]
|
||||||
|
public string SW { get; set; }
|
||||||
|
[BsonRepresentation(BsonType.ObjectId)]
|
||||||
|
public string W { get; set; }
|
||||||
|
[BsonRepresentation(BsonType.ObjectId)]
|
||||||
|
public string NW { get; set; }
|
||||||
|
|
||||||
|
public List<string> Players { get; set; } = [];
|
||||||
|
|
||||||
|
[BsonRepresentation(BsonType.ObjectId)]
|
||||||
|
public List<string> Content { get; set; } = [];
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
// Models/Player.cs
|
||||||
|
using MongoDB.Bson;
|
||||||
|
using MongoDB.Bson.Serialization.Attributes;
|
||||||
|
|
||||||
|
namespace GameAuthApi.Models;
|
||||||
|
|
||||||
|
public class Player
|
||||||
|
{
|
||||||
|
[BsonId]
|
||||||
|
[BsonRepresentation(BsonType.ObjectId)]
|
||||||
|
public string Id { get; set; }
|
||||||
|
|
||||||
|
public string UserId { get; set; } // Linked to user
|
||||||
|
public string Name { get; set; } // In-game player name
|
||||||
|
public string LocationId { get; set; } // Current location (nullable)
|
||||||
|
public string InventoryLocationId { get; set; } // Inventory location (nullable)
|
||||||
|
public int Climbing { get; set; } = 3; // Climbing skill level (default 3)
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
using MongoDB.Bson;
|
||||||
|
using MongoDB.Bson.Serialization.Attributes;
|
||||||
|
|
||||||
|
namespace GameAuthApi.Models;
|
||||||
|
|
||||||
|
public class Spawnable
|
||||||
|
{
|
||||||
|
[BsonId]
|
||||||
|
[BsonRepresentation(BsonType.ObjectId)]
|
||||||
|
public string Id { get; set; }
|
||||||
|
|
||||||
|
public string Name { get; set; }
|
||||||
|
public int SpawnRate { get; set; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
using System;
|
||||||
|
using MongoDB.Bson;
|
||||||
|
using MongoDB.Bson.Serialization.Attributes;
|
||||||
|
|
||||||
|
namespace GameAuthApi.Models;
|
||||||
|
|
||||||
|
public class User
|
||||||
|
{
|
||||||
|
[BsonId]
|
||||||
|
[BsonRepresentation(BsonType.ObjectId)]
|
||||||
|
public string Id { get; set; }
|
||||||
|
|
||||||
|
public string Username { get; set; }
|
||||||
|
public string PasswordHash { get; set; }
|
||||||
|
public string Role { get; set; } = "player";
|
||||||
|
public string RefreshToken { get; set; }
|
||||||
|
public DateTime RefreshTokenExpiry { get; set; }
|
||||||
|
public string Email { get; set; }
|
||||||
|
}
|
||||||
+83
@@ -0,0 +1,83 @@
|
|||||||
|
using GameAuthApi.Services;
|
||||||
|
using GameAuthApi.Middleware;
|
||||||
|
using Microsoft.AspNetCore.Builder;
|
||||||
|
using Microsoft.AspNetCore.Hosting;
|
||||||
|
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Microsoft.Extensions.Hosting;
|
||||||
|
using Microsoft.IdentityModel.Tokens;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
var builder = WebApplication.CreateBuilder(args);
|
||||||
|
|
||||||
|
builder.Services.AddControllers();
|
||||||
|
builder.Services.AddEndpointsApiExplorer();
|
||||||
|
builder.Services.AddSwaggerGen(c =>
|
||||||
|
{
|
||||||
|
c.SwaggerDoc("v1", new() { Title = "GameAuthApi", Version = "v1" });
|
||||||
|
|
||||||
|
c.AddSecurityDefinition("Bearer", new()
|
||||||
|
{
|
||||||
|
Name = "Authorization",
|
||||||
|
Type = Microsoft.OpenApi.Models.SecuritySchemeType.ApiKey,
|
||||||
|
Scheme = "Bearer",
|
||||||
|
BearerFormat = "JWT",
|
||||||
|
In = Microsoft.OpenApi.Models.ParameterLocation.Header,
|
||||||
|
Description = "Enter: `Bearer <your JWT token>`"
|
||||||
|
});
|
||||||
|
|
||||||
|
c.AddSecurityRequirement(new()
|
||||||
|
{
|
||||||
|
{
|
||||||
|
new Microsoft.OpenApi.Models.OpenApiSecurityScheme
|
||||||
|
{
|
||||||
|
Reference = new Microsoft.OpenApi.Models.OpenApiReference
|
||||||
|
{
|
||||||
|
Type = Microsoft.OpenApi.Models.ReferenceType.SecurityScheme,
|
||||||
|
Id = "Bearer"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
new string[] {}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
builder.Services.AddSingleton<UserService>();
|
||||||
|
builder.Services.AddSingleton<LocationService>();
|
||||||
|
builder.Services.AddSingleton<PlayerService>();
|
||||||
|
builder.Services.AddSingleton<SpawnableService>();
|
||||||
|
builder.Services.AddSingleton<ItemService>();
|
||||||
|
builder.Services.AddSingleton<BlacklistService>();
|
||||||
|
|
||||||
|
var jwtKey = builder.Configuration["Jwt:Key"];
|
||||||
|
var keyBytes = Encoding.UTF8.GetBytes(jwtKey);
|
||||||
|
|
||||||
|
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
|
||||||
|
.AddJwtBearer(options =>
|
||||||
|
{
|
||||||
|
options.TokenValidationParameters = new TokenValidationParameters
|
||||||
|
{
|
||||||
|
ValidateIssuer = true,
|
||||||
|
ValidateAudience = true,
|
||||||
|
ValidIssuer = builder.Configuration["Jwt:Issuer"],
|
||||||
|
ValidAudience = builder.Configuration["Jwt:Issuer"],
|
||||||
|
ValidateLifetime = true,
|
||||||
|
ValidateIssuerSigningKey = true,
|
||||||
|
IssuerSigningKey = new SymmetricSecurityKey(keyBytes)
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
var app = builder.Build();
|
||||||
|
|
||||||
|
app.UseSwagger();
|
||||||
|
app.UseSwaggerUI();
|
||||||
|
|
||||||
|
app.UseMiddleware<GameAuthApi.Middleware.TokenBlacklistMiddleware>();
|
||||||
|
|
||||||
|
app.UseAuthentication();
|
||||||
|
app.UseAuthorization();
|
||||||
|
app.MapControllers();
|
||||||
|
|
||||||
|
app.Run();
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
using System;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using GameAuthApi.Models;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
using MongoDB.Driver;
|
||||||
|
|
||||||
|
namespace GameAuthApi.Services;
|
||||||
|
|
||||||
|
public class BlacklistService
|
||||||
|
{
|
||||||
|
private readonly IMongoCollection<BlacklistedToken> _blacklist;
|
||||||
|
|
||||||
|
public BlacklistService(IConfiguration config)
|
||||||
|
{
|
||||||
|
var client = new MongoClient(config["MongoDB:ConnectionString"]);
|
||||||
|
var db = client.GetDatabase(config["MongoDB:DatabaseName"]);
|
||||||
|
_blacklist = db.GetCollection<BlacklistedToken>("BlacklistedTokens");
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task AddToBlacklistAsync(string token, DateTime expiry)
|
||||||
|
{
|
||||||
|
var entry = new BlacklistedToken { Token = token, Expiry = expiry };
|
||||||
|
await _blacklist.InsertOneAsync(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<bool> IsTokenBlacklistedAsync(string token)
|
||||||
|
{
|
||||||
|
var exists = await _blacklist.Find(x => x.Token == token && x.Expiry > DateTime.UtcNow).FirstOrDefaultAsync();
|
||||||
|
return exists != null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using GameAuthApi.Models;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
using MongoDB.Driver;
|
||||||
|
|
||||||
|
namespace GameAuthApi.Services;
|
||||||
|
|
||||||
|
public class ItemService
|
||||||
|
{
|
||||||
|
private readonly IMongoCollection<Item> _items;
|
||||||
|
|
||||||
|
public ItemService(IConfiguration config)
|
||||||
|
{
|
||||||
|
var client = new MongoClient(config["MongoDB:ConnectionString"]);
|
||||||
|
var db = client.GetDatabase(config["MongoDB:DatabaseName"]);
|
||||||
|
_items = db.GetCollection<Item>("Items");
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task CreateAsync(Item item)
|
||||||
|
{
|
||||||
|
await _items.InsertOneAsync(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<List<Item>> GetByLocationAsync(string locationId)
|
||||||
|
{
|
||||||
|
return await _items.Find(i => i.LocationId == locationId).ToListAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<Item> GetByIdAsync(string id)
|
||||||
|
{
|
||||||
|
return await _items.Find(i => i.Id == id).FirstOrDefaultAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task UpdateAsync(Item item)
|
||||||
|
{
|
||||||
|
await _items.ReplaceOneAsync(i => i.Id == item.Id, item);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
using System.Threading.Tasks;
|
||||||
|
using GameAuthApi.Models;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
using MongoDB.Bson;
|
||||||
|
using MongoDB.Driver;
|
||||||
|
|
||||||
|
namespace GameAuthApi.Services;
|
||||||
|
|
||||||
|
public class LocationService
|
||||||
|
{
|
||||||
|
private readonly IMongoCollection<Location> _locations;
|
||||||
|
|
||||||
|
public LocationService(IConfiguration config)
|
||||||
|
{
|
||||||
|
var client = new MongoClient(config["MongoDB:ConnectionString"]);
|
||||||
|
var db = client.GetDatabase(config["MongoDB:DatabaseName"]);
|
||||||
|
_locations = db.GetCollection<Location>("Locations");
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<Location> GetByIdAsync(string id)
|
||||||
|
{
|
||||||
|
if (!ObjectId.TryParse(id, out _))
|
||||||
|
return null; // prevent crash if id is invalid
|
||||||
|
|
||||||
|
return await _locations.Find(x => x.Id == id).FirstOrDefaultAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task CreateAsync(Location loc) =>
|
||||||
|
await _locations.InsertOneAsync(loc);
|
||||||
|
|
||||||
|
public async Task DeleteAsync(string id) =>
|
||||||
|
await _locations.DeleteOneAsync(loc => loc.Id == id);
|
||||||
|
public async Task UpdateAsync(Location loc) =>
|
||||||
|
await _locations.ReplaceOneAsync(l => l.Id == loc.Id, loc);
|
||||||
|
|
||||||
|
public async Task AddPlayerToLocationAsync(string locationId, string playerId)
|
||||||
|
{
|
||||||
|
var update = Builders<Location>.Update.AddToSet(l => l.Players, playerId);
|
||||||
|
await _locations.UpdateOneAsync(l => l.Id == locationId, update);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<Location> GetByCoordinatesAsync(int x, int y, int z)
|
||||||
|
{
|
||||||
|
return await _locations.Find(loc => loc.X == x && loc.Y == y && loc.Z == z).FirstOrDefaultAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<Location> GetSpawnLocationAsync()
|
||||||
|
{
|
||||||
|
return await _locations.Find(loc => loc.X == 0 && loc.Y == 0).FirstOrDefaultAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task RemovePlayerFromLocationAsync(string locationId, string playerId)
|
||||||
|
{
|
||||||
|
var update = Builders<Location>.Update.Pull(l => l.Players, playerId);
|
||||||
|
await _locations.UpdateOneAsync(l => l.Id == locationId, update);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task AddItemToLocationAsync(string locationId, string itemId)
|
||||||
|
{
|
||||||
|
var update = Builders<Location>.Update.Push(l => l.Content, itemId);
|
||||||
|
await _locations.UpdateOneAsync(l => l.Id == locationId, update);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task RemoveItemFromLocationAsync(string locationId, string itemId)
|
||||||
|
{
|
||||||
|
var update = Builders<Location>.Update.Pull(l => l.Content, itemId);
|
||||||
|
await _locations.UpdateOneAsync(l => l.Id == locationId, update);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
// Services/PlayerService.cs
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using GameAuthApi.Models;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
using MongoDB.Driver;
|
||||||
|
|
||||||
|
namespace GameAuthApi.Services;
|
||||||
|
|
||||||
|
public class PlayerService
|
||||||
|
{
|
||||||
|
private readonly IMongoCollection<Player> _players;
|
||||||
|
|
||||||
|
public PlayerService(IConfiguration config)
|
||||||
|
{
|
||||||
|
var client = new MongoClient(config["MongoDB:ConnectionString"]);
|
||||||
|
var db = client.GetDatabase(config["MongoDB:DatabaseName"]);
|
||||||
|
_players = db.GetCollection<Player>("Players");
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<Player> GetByUserIdAsync(string userId) =>
|
||||||
|
await _players.Find(p => p.UserId == userId).FirstOrDefaultAsync();
|
||||||
|
|
||||||
|
public async Task<List<Player>> GetByLocationIdAsync(string locationId)
|
||||||
|
{
|
||||||
|
return await _players.Find(p => p.LocationId == locationId).ToListAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<Player> GetByIdAsync(string id) =>
|
||||||
|
await _players.Find(p => p.Id == id).FirstOrDefaultAsync();
|
||||||
|
|
||||||
|
public async Task CreateAsync(Player player) =>
|
||||||
|
await _players.InsertOneAsync(player);
|
||||||
|
|
||||||
|
public async Task UpdateAsync(Player player)
|
||||||
|
{
|
||||||
|
await _players.ReplaceOneAsync(p => p.Id == player.Id, player);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task DeleteAsync(string id)
|
||||||
|
{
|
||||||
|
await _players.DeleteOneAsync(p => p.Id == id);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using GameAuthApi.Models;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
using MongoDB.Driver;
|
||||||
|
|
||||||
|
namespace GameAuthApi.Services;
|
||||||
|
|
||||||
|
public class SpawnableService
|
||||||
|
{
|
||||||
|
private readonly IMongoCollection<Spawnable> _spawnables;
|
||||||
|
|
||||||
|
public SpawnableService(IConfiguration config)
|
||||||
|
{
|
||||||
|
var client = new MongoClient(config["MongoDB:ConnectionString"]);
|
||||||
|
var db = client.GetDatabase(config["MongoDB:DatabaseName"]);
|
||||||
|
_spawnables = db.GetCollection<Spawnable>("Spawnables");
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task CreateAsync(Spawnable spawnable)
|
||||||
|
{
|
||||||
|
await _spawnables.InsertOneAsync(spawnable);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<List<Spawnable>> GetAllAsync()
|
||||||
|
{
|
||||||
|
return await _spawnables.Find(_ => true).ToListAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
using System.Threading.Tasks;
|
||||||
|
using GameAuthApi.Models;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
using MongoDB.Driver;
|
||||||
|
|
||||||
|
namespace GameAuthApi.Services;
|
||||||
|
|
||||||
|
public class UserService
|
||||||
|
{
|
||||||
|
private readonly IMongoCollection<User> _users;
|
||||||
|
|
||||||
|
public UserService(IConfiguration config)
|
||||||
|
{
|
||||||
|
var client = new MongoClient(config["MongoDB:ConnectionString"]);
|
||||||
|
var database = client.GetDatabase(config["MongoDB:DatabaseName"]);
|
||||||
|
_users = database.GetCollection<User>("Users");
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<User> GetByUsernameAsync(string username) =>
|
||||||
|
await _users.Find(u => u.Username == username).FirstOrDefaultAsync();
|
||||||
|
|
||||||
|
public async Task CreateAsync(User user) =>
|
||||||
|
await _users.InsertOneAsync(user);
|
||||||
|
|
||||||
|
public async Task UpdateAsync(User user) =>
|
||||||
|
await _users.ReplaceOneAsync(u => u.Id == user.Id, user);
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"MongoDB": {
|
||||||
|
"ConnectionString": "mongodb://192.168.86.50:27017",
|
||||||
|
"DatabaseName": "GameDb"
|
||||||
|
},
|
||||||
|
"Jwt": {
|
||||||
|
"Key": "SuperUltraSecureJwtKeyWithAtLeast32Chars!!",
|
||||||
|
"Issuer": "GameAuthApi"
|
||||||
|
},
|
||||||
|
"Logging": {
|
||||||
|
"LogLevel": {
|
||||||
|
"Default": "Information"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"AllowedHosts": "*"
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user