Adding upkeep
This commit is contained in:
@@ -21,6 +21,7 @@ public class UnitTrainingService
|
||||
private readonly int _defaultScoutTrainingSeconds;
|
||||
private readonly int _defaultArcherTrainingSeconds;
|
||||
private readonly int _defaultPeasantTrainingSeconds;
|
||||
private readonly int _unitMovementPerTick;
|
||||
private readonly int _visibilityDepth;
|
||||
|
||||
public UnitTrainingService(IConfiguration cfg, ResourceService resources, GameSettingsService settings)
|
||||
@@ -47,6 +48,9 @@ public class UnitTrainingService
|
||||
_defaultPeasantTrainingSeconds = int.TryParse(cfg["Units:PeasantTrainingSeconds"], out var peasantTrainingSeconds)
|
||||
? Math.Max(1, peasantTrainingSeconds)
|
||||
: 60;
|
||||
_unitMovementPerTick = int.TryParse(cfg["Units:UnitMovementPerTick"], out var unitMovementPerTick)
|
||||
? Math.Max(1, unitMovementPerTick)
|
||||
: 1;
|
||||
_visibilityDepth = int.TryParse(cfg["World:VisibilityDepth"], out var visibilityDepth) ? Math.Max(0, visibilityDepth) : 3;
|
||||
|
||||
_training.Indexes.CreateOne(new CreateIndexModel<UnitTraining>(
|
||||
@@ -65,6 +69,8 @@ public class UnitTrainingService
|
||||
public async Task<PlayerUnitsResponse> GetMineAsync(string username)
|
||||
{
|
||||
await CompleteFinishedTrainingAsync(username);
|
||||
await CompletePendingMovementAsync(username);
|
||||
await RefillMovementAsync(username);
|
||||
await _training.DeleteManyAsync(x => x.Username == username && x.Status == "Consumed");
|
||||
|
||||
var allTraining = await _training.Find(x => x.Username == username).ToListAsync();
|
||||
@@ -167,6 +173,9 @@ public class UnitTrainingService
|
||||
|
||||
public async Task<List<UnitInstance>> MoveSquadAsync(string username, MoveUnitSquadRequest request)
|
||||
{
|
||||
await CompletePendingMovementAsync(username);
|
||||
await RefillMovementAsync(username);
|
||||
|
||||
var normalizedUnitType = NormalizeUnitType(request.UnitType);
|
||||
if (normalizedUnitType != ArcherUnitType)
|
||||
{
|
||||
@@ -192,6 +201,7 @@ public class UnitTrainingService
|
||||
var units = await _units.Find(x =>
|
||||
x.Username == username &&
|
||||
x.UnitType == ArcherUnitType &&
|
||||
x.Status == "Idle" &&
|
||||
x.Q == request.FromQ &&
|
||||
x.R == request.FromR)
|
||||
.ToListAsync();
|
||||
@@ -201,24 +211,35 @@ public class UnitTrainingService
|
||||
return [];
|
||||
}
|
||||
|
||||
if (units.Any(x => x.MovementRemaining <= 0))
|
||||
{
|
||||
throw new InvalidOperationException("That squad has no movement remaining this tick.");
|
||||
}
|
||||
|
||||
var movementCompletesAt = now.AddMinutes(1);
|
||||
await _units.UpdateManyAsync(
|
||||
x => x.Username == username &&
|
||||
x.UnitType == ArcherUnitType &&
|
||||
x.Status == "Idle" &&
|
||||
x.Q == request.FromQ &&
|
||||
x.R == request.FromR,
|
||||
Builders<UnitInstance>.Update
|
||||
.Set(x => x.Q, request.ToQ)
|
||||
.Set(x => x.R, request.ToR)
|
||||
.Set(x => x.Status, "Idle")
|
||||
.Set(x => x.Status, "Moving")
|
||||
.Inc(x => x.MovementRemaining, -1)
|
||||
.Set(x => x.DestinationQ, request.ToQ)
|
||||
.Set(x => x.DestinationR, request.ToR)
|
||||
.Set(x => x.MovementStartedAtUtc, now)
|
||||
.Set(x => x.MovementCompletesAtUtc, movementCompletesAt)
|
||||
.Set(x => x.UpdatedAtUtc, now));
|
||||
|
||||
await ClaimTargetIfEmptyAsync(username, request.ToQ, request.ToR, now);
|
||||
|
||||
return await _units.Find(x =>
|
||||
x.Username == username &&
|
||||
x.UnitType == ArcherUnitType &&
|
||||
x.Q == request.ToQ &&
|
||||
x.R == request.ToR)
|
||||
x.Status == "Moving" &&
|
||||
x.Q == request.FromQ &&
|
||||
x.R == request.FromR &&
|
||||
x.DestinationQ == request.ToQ &&
|
||||
x.DestinationR == request.ToR)
|
||||
.ToListAsync();
|
||||
}
|
||||
|
||||
@@ -234,6 +255,86 @@ public class UnitTrainingService
|
||||
.FirstOrDefaultAsync();
|
||||
}
|
||||
|
||||
private async Task CompletePendingMovementAsync(string username)
|
||||
{
|
||||
var now = DateTime.UtcNow;
|
||||
var movementPerTick = await _settings.GetIntAsync(GameSettingsService.UnitMovementPerTick, _unitMovementPerTick);
|
||||
var movingUnits = await _units.Find(x =>
|
||||
x.Username == username &&
|
||||
x.Status == "Moving" &&
|
||||
x.MovementCompletesAtUtc != null &&
|
||||
x.MovementCompletesAtUtc <= now)
|
||||
.ToListAsync();
|
||||
|
||||
foreach (var unit in movingUnits)
|
||||
{
|
||||
if (unit.DestinationQ is null || unit.DestinationR is null)
|
||||
{
|
||||
await _units.UpdateOneAsync(
|
||||
x => x.Id == unit.Id,
|
||||
Builders<UnitInstance>.Update
|
||||
.Set(x => x.Status, "Idle")
|
||||
.Set(x => x.MovementPerTick, movementPerTick)
|
||||
.Set(x => x.MovementRemaining, movementPerTick)
|
||||
.Unset(x => x.MovementStartedAtUtc)
|
||||
.Unset(x => x.MovementCompletesAtUtc)
|
||||
.Set(x => x.UpdatedAtUtc, now));
|
||||
continue;
|
||||
}
|
||||
|
||||
await _units.UpdateOneAsync(
|
||||
x => x.Id == unit.Id,
|
||||
Builders<UnitInstance>.Update
|
||||
.Set(x => x.Q, unit.DestinationQ.Value)
|
||||
.Set(x => x.R, unit.DestinationR.Value)
|
||||
.Set(x => x.Status, "Idle")
|
||||
.Set(x => x.MovementPerTick, movementPerTick)
|
||||
.Set(x => x.MovementRemaining, movementPerTick)
|
||||
.Set(x => x.LastMovementRefillAtUtc, now)
|
||||
.Unset(x => x.DestinationQ)
|
||||
.Unset(x => x.DestinationR)
|
||||
.Unset(x => x.MovementStartedAtUtc)
|
||||
.Unset(x => x.MovementCompletesAtUtc)
|
||||
.Set(x => x.UpdatedAtUtc, now));
|
||||
|
||||
if (unit.UnitType == ArcherUnitType)
|
||||
{
|
||||
await ClaimTargetIfEmptyAsync(username, unit.DestinationQ.Value, unit.DestinationR.Value, now);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async Task RefillMovementAsync(string username)
|
||||
{
|
||||
var now = DateTime.UtcNow;
|
||||
var movementPerTick = await _settings.GetIntAsync(GameSettingsService.UnitMovementPerTick, _unitMovementPerTick);
|
||||
var units = await _units.Find(x => x.Username == username && x.Status != "Moving" && x.Status != "MovingToWork").ToListAsync();
|
||||
|
||||
foreach (var unit in units)
|
||||
{
|
||||
var lastRefill = unit.LastMovementRefillAtUtc.Year < 2000 ? now : unit.LastMovementRefillAtUtc;
|
||||
var elapsedTicks = (int)Math.Floor((now - lastRefill).TotalMinutes);
|
||||
var movementRemaining = elapsedTicks > 0
|
||||
? movementPerTick
|
||||
: Math.Min(unit.MovementRemaining, movementPerTick);
|
||||
if (elapsedTicks <= 0 && unit.MovementPerTick == movementPerTick && unit.MovementRemaining == movementRemaining)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var update = Builders<UnitInstance>.Update
|
||||
.Set(x => x.MovementPerTick, movementPerTick)
|
||||
.Set(x => x.MovementRemaining, movementRemaining)
|
||||
.Set(x => x.UpdatedAtUtc, now);
|
||||
if (elapsedTicks > 0)
|
||||
{
|
||||
update = update.Set(x => x.LastMovementRefillAtUtc, lastRefill.AddMinutes(elapsedTicks));
|
||||
}
|
||||
|
||||
await _units.UpdateOneAsync(x => x.Id == unit.Id, update);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task CompleteFinishedBuildingsAsync(string username)
|
||||
{
|
||||
var now = DateTime.UtcNow;
|
||||
@@ -376,6 +477,7 @@ public class UnitTrainingService
|
||||
continue;
|
||||
}
|
||||
|
||||
var movementPerTick = await _settings.GetIntAsync(GameSettingsService.UnitMovementPerTick, _unitMovementPerTick);
|
||||
var unit = new UnitInstance
|
||||
{
|
||||
Username = completed.Username,
|
||||
@@ -383,6 +485,9 @@ public class UnitTrainingService
|
||||
Q = completed.OriginQ ?? 0,
|
||||
R = completed.OriginR ?? 0,
|
||||
Status = "Idle",
|
||||
MovementPerTick = movementPerTick,
|
||||
MovementRemaining = movementPerTick,
|
||||
LastMovementRefillAtUtc = now,
|
||||
SourceTrainingId = completed.Id,
|
||||
CreatedAtUtc = now,
|
||||
UpdatedAtUtc = now
|
||||
|
||||
Reference in New Issue
Block a user