wip client "secret"
This commit is contained in:
parent
698271ae9f
commit
b192cd7da0
|
@ -22,8 +22,8 @@ internal sealed class CollideBulletsWithTanks(
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (bullet.Owner != tank.Owner)
|
if (bullet.Owner != tank.Owner)
|
||||||
bullet.Owner.Kills++;
|
bullet.Owner.Scores.Kills++;
|
||||||
tank.Owner.Deaths++;
|
tank.Owner.Scores.Deaths++;
|
||||||
|
|
||||||
tanks.Remove(tank);
|
tanks.Remove(tank);
|
||||||
spawnQueue.EnqueueForDelayedSpawn(tank.Owner);
|
spawnQueue.EnqueueForDelayedSpawn(tank.Owner);
|
||||||
|
|
|
@ -36,7 +36,7 @@ internal sealed class MoveTanks(
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
var angle = tank.Rotation * 2d * Math.PI;
|
var angle = tank.Orientation / 16d * 2d * Math.PI;
|
||||||
var newX = tank.Position.X + Math.Sin(angle) * speed;
|
var newX = tank.Position.X + Math.Sin(angle) * speed;
|
||||||
var newY = tank.Position.Y - Math.Cos(angle) * speed;
|
var newY = tank.Position.Y - Math.Cos(angle) * speed;
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,10 @@
|
||||||
namespace TanksServer.GameLogic;
|
namespace TanksServer.GameLogic;
|
||||||
|
|
||||||
internal sealed class RotateTanks(TankManager tanks, IOptions<TanksConfiguration> options) : ITickStep
|
internal sealed class RotateTanks(
|
||||||
|
TankManager tanks,
|
||||||
|
IOptions<TanksConfiguration> options,
|
||||||
|
ILogger<RotateTanks> logger
|
||||||
|
) : ITickStep
|
||||||
{
|
{
|
||||||
private readonly TanksConfiguration _config = options.Value;
|
private readonly TanksConfiguration _config = options.Value;
|
||||||
|
|
||||||
|
@ -10,10 +14,20 @@ internal sealed class RotateTanks(TankManager tanks, IOptions<TanksConfiguration
|
||||||
{
|
{
|
||||||
var player = tank.Owner;
|
var player = tank.Owner;
|
||||||
|
|
||||||
if (player.Controls.TurnLeft)
|
switch (player.Controls)
|
||||||
tank.Rotation -= _config.TurnSpeed / 16d;
|
{
|
||||||
if (player.Controls.TurnRight)
|
case { TurnRight: true, TurnLeft: true }:
|
||||||
tank.Rotation += _config.TurnSpeed / 16d;
|
case { TurnRight: false, TurnLeft: false }:
|
||||||
|
continue;
|
||||||
|
case { TurnLeft: true }:
|
||||||
|
tank.Rotation -= _config.TurnSpeed;
|
||||||
|
break;
|
||||||
|
case { TurnRight: true }:
|
||||||
|
tank.Rotation += _config.TurnSpeed;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.LogTrace("rotated tank to {}", tank.Rotation);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
|
|
|
@ -25,12 +25,13 @@ internal sealed class ShootFromTanks(
|
||||||
|
|
||||||
tank.NextShotAfter = DateTime.Now.AddMilliseconds(_config.ShootDelayMs);
|
tank.NextShotAfter = DateTime.Now.AddMilliseconds(_config.ShootDelayMs);
|
||||||
|
|
||||||
var angle = tank.Rotation * 2 * Math.PI;
|
var rotation = tank.Orientation / 16d;
|
||||||
|
var angle = rotation * 2d * Math.PI;
|
||||||
var position = new FloatPosition(
|
var position = new FloatPosition(
|
||||||
tank.Position.X + Math.Sin(angle) * _config.BulletSpeed,
|
tank.Position.X + Math.Sin(angle) * _config.BulletSpeed,
|
||||||
tank.Position.Y - Math.Cos(angle) * _config.BulletSpeed
|
tank.Position.Y - Math.Cos(angle) * _config.BulletSpeed
|
||||||
);
|
);
|
||||||
|
|
||||||
bulletManager.Spawn(new Bullet(tank.Owner, position, tank.Rotation));
|
bulletManager.Spawn(new Bullet(tank.Owner, position, rotation));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,12 +32,11 @@ internal sealed class DrawTanksStep : IDrawStep
|
||||||
foreach (var tank in _tanks)
|
foreach (var tank in _tanks)
|
||||||
{
|
{
|
||||||
var tankPosition = tank.Bounds.TopLeft;
|
var tankPosition = tank.Bounds.TopLeft;
|
||||||
var orientation = (int)Math.Round(tank.Rotation * 16d) % 16;
|
|
||||||
|
|
||||||
for (byte dy = 0; dy < MapService.TileSize; dy++)
|
for (byte dy = 0; dy < MapService.TileSize; dy++)
|
||||||
for (byte dx = 0; dx < MapService.TileSize; dx++)
|
for (byte dx = 0; dx < MapService.TileSize; dx++)
|
||||||
{
|
{
|
||||||
if (!TankSpriteAt(dx, dy, orientation))
|
if (!TankSpriteAt(dx, dy, tank.Orientation))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
var (x, y) = tankPosition.GetPixelRelative(dx, dy);
|
var (x, y) = tankPosition.GetPixelRelative(dx, dy);
|
||||||
|
|
|
@ -3,4 +3,6 @@ using System.Text.Json.Serialization;
|
||||||
namespace TanksServer.Interactivity;
|
namespace TanksServer.Interactivity;
|
||||||
|
|
||||||
[JsonSerializable(typeof(Player))]
|
[JsonSerializable(typeof(Player))]
|
||||||
|
[JsonSerializable(typeof(IEnumerable<Player>))]
|
||||||
|
[JsonSerializable(typeof(Guid))]
|
||||||
internal sealed partial class AppSerializerContext : JsonSerializerContext;
|
internal sealed partial class AppSerializerContext : JsonSerializerContext;
|
||||||
|
|
|
@ -7,9 +7,19 @@ internal sealed class PlayerServer(ILogger<PlayerServer> logger, SpawnQueue spaw
|
||||||
{
|
{
|
||||||
private readonly ConcurrentDictionary<string, Player> _players = new();
|
private readonly ConcurrentDictionary<string, Player> _players = new();
|
||||||
|
|
||||||
public Player GetOrAdd(string name)
|
public Player? GetOrAdd(string name, Guid id)
|
||||||
{
|
{
|
||||||
var player = _players.GetOrAdd(name, AddAndSpawn);
|
Player AddAndSpawn()
|
||||||
|
{
|
||||||
|
var player = new Player(name, id);
|
||||||
|
spawnQueue.EnqueueForImmediateSpawn(player);
|
||||||
|
return player;
|
||||||
|
}
|
||||||
|
|
||||||
|
var player = _players.GetOrAdd(name, _ => AddAndSpawn());
|
||||||
|
if (player.Id != id)
|
||||||
|
return null;
|
||||||
|
|
||||||
logger.LogInformation("player {} (re)joined", player.Id);
|
logger.LogInformation("player {} (re)joined", player.Id);
|
||||||
return player;
|
return player;
|
||||||
}
|
}
|
||||||
|
@ -29,11 +39,4 @@ internal sealed class PlayerServer(ILogger<PlayerServer> logger, SpawnQueue spaw
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<Player> GetAll() => _players.Values;
|
public IEnumerable<Player> GetAll() => _players.Values;
|
||||||
|
|
||||||
private Player AddAndSpawn(string name)
|
|
||||||
{
|
|
||||||
var player = new Player(name);
|
|
||||||
spawnQueue.EnqueueForImmediateSpawn(player);
|
|
||||||
return player;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -71,13 +71,13 @@ internal sealed class SendToServicePointDisplay : ITickStep
|
||||||
private void RefreshScores()
|
private void RefreshScores()
|
||||||
{
|
{
|
||||||
var playersToDisplay = _players.GetAll()
|
var playersToDisplay = _players.GetAll()
|
||||||
.OrderByDescending(p => p.Kills)
|
.OrderByDescending(p => p.Scores.Kills)
|
||||||
.Take(ScoresPlayerRows);
|
.Take(ScoresPlayerRows);
|
||||||
|
|
||||||
ushort row = 2;
|
ushort row = 2;
|
||||||
foreach (var p in playersToDisplay)
|
foreach (var p in playersToDisplay)
|
||||||
{
|
{
|
||||||
var score = p.Kills.ToString();
|
var score = p.Scores.Kills.ToString();
|
||||||
var nameLength = Math.Min(p.Name.Length, ScoresWidth - score.Length - 1);
|
var nameLength = Math.Min(p.Name.Length, ScoresWidth - score.Length - 1);
|
||||||
|
|
||||||
var name = p.Name[..nameLength];
|
var name = p.Name[..nameLength];
|
||||||
|
|
|
@ -2,17 +2,15 @@ using System.Text.Json.Serialization;
|
||||||
|
|
||||||
namespace TanksServer.Models;
|
namespace TanksServer.Models;
|
||||||
|
|
||||||
internal sealed class Player(string name)
|
internal sealed class Player(string name, Guid id)
|
||||||
{
|
{
|
||||||
public string Name => name;
|
public string Name => name;
|
||||||
|
|
||||||
public Guid Id { get; } = Guid.NewGuid();
|
[JsonIgnore] public Guid Id => id;
|
||||||
|
|
||||||
[JsonIgnore] public PlayerControls Controls { get; } = new();
|
[JsonIgnore] public PlayerControls Controls { get; } = new();
|
||||||
|
|
||||||
public int Kills { get; set; }
|
public Scores Scores { get; } = new();
|
||||||
|
|
||||||
public int Deaths { get; set; }
|
|
||||||
|
|
||||||
public DateTime LastInput { get; set; } = DateTime.Now;
|
public DateTime LastInput { get; set; } = DateTime.Now;
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,8 +23,8 @@ internal static class PositionHelpers
|
||||||
public static FloatPosition ToFloatPosition(this PixelPosition position) => new(position.X, position.Y);
|
public static FloatPosition ToFloatPosition(this PixelPosition position) => new(position.X, position.Y);
|
||||||
|
|
||||||
|
|
||||||
public static double Distance(this FloatPosition p1, FloatPosition p2) =>
|
public static double Distance(this FloatPosition p1, FloatPosition p2)
|
||||||
Math.Sqrt(
|
=> Math.Sqrt(
|
||||||
Math.Pow(p1.X - p2.X, 2) +
|
Math.Pow(p1.X - p2.X, 2) +
|
||||||
Math.Pow(p1.Y - p2.Y, 2)
|
Math.Pow(p1.Y - p2.Y, 2)
|
||||||
);
|
);
|
||||||
|
|
8
TanksServer/Models/Scores.cs
Normal file
8
TanksServer/Models/Scores.cs
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
namespace TanksServer.Models;
|
||||||
|
|
||||||
|
internal sealed record class Scores(int Kills = 0, int Deaths = 0)
|
||||||
|
{
|
||||||
|
public int Kills { get; set; } = Kills;
|
||||||
|
|
||||||
|
public int Deaths { get; set; } = Deaths;
|
||||||
|
}
|
|
@ -1,5 +1,4 @@
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using TanksServer.GameLogic;
|
|
||||||
|
|
||||||
namespace TanksServer.Models;
|
namespace TanksServer.Models;
|
||||||
|
|
||||||
|
@ -28,12 +27,14 @@ internal sealed class Tank(Player player, FloatPosition spawnPosition) : IMapEnt
|
||||||
|
|
||||||
public PixelBounds Bounds => GetBoundsForCenter(Position);
|
public PixelBounds Bounds => GetBoundsForCenter(Position);
|
||||||
|
|
||||||
|
public int Orientation => (int)Math.Round(Rotation * 16) % 16;
|
||||||
|
|
||||||
public static PixelBounds GetBoundsForCenter(FloatPosition position)
|
public static PixelBounds GetBoundsForCenter(FloatPosition position)
|
||||||
{
|
{
|
||||||
var pixelPosition = position.ToPixelPosition();
|
var pixelPosition = position.ToPixelPosition();
|
||||||
return new PixelBounds(
|
return new PixelBounds(
|
||||||
pixelPosition.GetPixelRelative(-3, -3),
|
pixelPosition.GetPixelRelative(-4, -4),
|
||||||
pixelPosition.GetPixelRelative(4, 4)
|
pixelPosition.GetPixelRelative(3, 3)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,18 +25,29 @@ public static class Program
|
||||||
app.UseDefaultFiles(new DefaultFilesOptions { FileProvider = clientFileProvider });
|
app.UseDefaultFiles(new DefaultFilesOptions { FileProvider = clientFileProvider });
|
||||||
app.UseStaticFiles(new StaticFileOptions { FileProvider = clientFileProvider });
|
app.UseStaticFiles(new StaticFileOptions { FileProvider = clientFileProvider });
|
||||||
|
|
||||||
app.MapGet("/player", playerService.GetOrAdd);
|
app.MapPost("/player", (string name, Guid id) =>
|
||||||
|
{
|
||||||
|
var player = playerService.GetOrAdd(name, id);
|
||||||
|
return player != null
|
||||||
|
? Results.Ok(player.Id)
|
||||||
|
: Results.Unauthorized();
|
||||||
|
});
|
||||||
|
app.MapGet("/player", ([FromQuery] Guid id) =>
|
||||||
|
playerService.TryGet(id, out var foundPlayer)
|
||||||
|
? Results.Ok((object?)foundPlayer)
|
||||||
|
: Results.NotFound()
|
||||||
|
);
|
||||||
|
|
||||||
app.Map("/screen", async context =>
|
app.MapGet("/scores", () => playerService.GetAll());
|
||||||
|
|
||||||
|
app.Map("/screen", async (HttpContext context) =>
|
||||||
{
|
{
|
||||||
if (!context.WebSockets.IsWebSocketRequest)
|
if (!context.WebSockets.IsWebSocketRequest)
|
||||||
{
|
return Results.BadRequest();
|
||||||
context.Response.StatusCode = StatusCodes.Status400BadRequest;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
using var ws = await context.WebSockets.AcceptWebSocketAsync();
|
using var ws = await context.WebSockets.AcceptWebSocketAsync();
|
||||||
await clientScreenServer.HandleClient(ws);
|
await clientScreenServer.HandleClient(ws);
|
||||||
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
app.Map("/controls", async (HttpContext context, [FromQuery] Guid playerId) =>
|
app.Map("/controls", async (HttpContext context, [FromQuery] Guid playerId) =>
|
||||||
|
@ -49,7 +60,7 @@ public static class Program
|
||||||
|
|
||||||
using var ws = await context.WebSockets.AcceptWebSocketAsync();
|
using var ws = await context.WebSockets.AcceptWebSocketAsync();
|
||||||
await controlsServer.HandleClient(ws, player);
|
await controlsServer.HandleClient(ws, player);
|
||||||
return Results.Ok();
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
app.Run();
|
app.Run();
|
||||||
|
|
|
@ -1,33 +1,34 @@
|
||||||
{
|
{
|
||||||
"Logging": {
|
"Logging": {
|
||||||
"LogLevel": {
|
"LogLevel": {
|
||||||
"Default": "Information",
|
"Default": "Information",
|
||||||
"Microsoft.AspNetCore": "Warning",
|
"Microsoft.AspNetCore": "Warning",
|
||||||
"TanksServer": "Debug",
|
"TanksServer": "Debug",
|
||||||
"Microsoft.AspNetCore.HttpLogging": "Information"
|
"Microsoft.AspNetCore.HttpLogging": "Information",
|
||||||
|
"TanksServer.GameLogic.RotateTanks": "Trace"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"AllowedHosts": "*",
|
||||||
|
"Kestrel": {
|
||||||
|
"Endpoints": {
|
||||||
|
"Http": {
|
||||||
|
"Url": "http://localhost:3000"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ServicePointDisplay": {
|
||||||
|
"Enable": true,
|
||||||
|
"Hostname": "172.23.42.29",
|
||||||
|
"Port": 2342
|
||||||
|
},
|
||||||
|
"Tanks": {
|
||||||
|
"MoveSpeed": 1.5,
|
||||||
|
"TurnSpeed": 0.02,
|
||||||
|
"ShootDelayMs": 450,
|
||||||
|
"BulletSpeed":4
|
||||||
|
},
|
||||||
|
"Players": {
|
||||||
|
"SpawnDelayMs": 3000,
|
||||||
|
"IdleTimeoutMs": 30000
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"AllowedHosts": "*",
|
|
||||||
"Kestrel": {
|
|
||||||
"Endpoints": {
|
|
||||||
"Http": {
|
|
||||||
"Url": "http://localhost:3000"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"ServicePointDisplay": {
|
|
||||||
"Enable": true,
|
|
||||||
"Hostname": "172.23.42.29",
|
|
||||||
"Port": 2342
|
|
||||||
},
|
|
||||||
"Tanks": {
|
|
||||||
"MoveSpeed": 1.4,
|
|
||||||
"TurnSpeed": 0.4,
|
|
||||||
"ShootDelayMs": 400,
|
|
||||||
"BulletSpeed": 3
|
|
||||||
},
|
|
||||||
"Players": {
|
|
||||||
"SpawnDelayMs": 3000,
|
|
||||||
"IdleTimeoutMs": 30000
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
8
TanksServer/userRequests.http
Normal file
8
TanksServer/userRequests.http
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
POST localhost/player?name=test&id=a31d35c2-1d9e-4a34-93e5-680195c6a9d2
|
||||||
|
|
||||||
|
###
|
||||||
|
|
||||||
|
GET localhost/scores
|
||||||
|
|
||||||
|
###
|
||||||
|
|
Loading…
Reference in a new issue