Updating movement
This commit is contained in:
@@ -288,7 +288,7 @@ public class LocationService
|
||||
var location = await GetAsync(request.Q, request.R);
|
||||
if (location is null ||
|
||||
!string.Equals(location.OwnerUsername, username, StringComparison.OrdinalIgnoreCase) ||
|
||||
string.IsNullOrWhiteSpace(location.BuildingType) ||
|
||||
!CanAssignWorkerToBuilding(location.BuildingType) ||
|
||||
location.BuildingStatus == "Building" ||
|
||||
!string.IsNullOrWhiteSpace(location.WorkerUnitId))
|
||||
{
|
||||
@@ -314,7 +314,7 @@ public class LocationService
|
||||
.Set(x => x.DestinationQ, request.Q)
|
||||
.Set(x => x.DestinationR, request.R)
|
||||
.Set(x => x.MovementStartedAtUtc, now)
|
||||
.Set(x => x.MovementCompletesAtUtc, now.AddMinutes(Math.Max(1, HexDistance(unit.Q, unit.R, request.Q, request.R))))
|
||||
.Set(x => x.MovementCompletesAtUtc, now.AddMinutes(1))
|
||||
.Set(x => x.UpdatedAtUtc, now));
|
||||
if (claimed.ModifiedCount == 0)
|
||||
{
|
||||
@@ -535,23 +535,29 @@ public class LocationService
|
||||
|
||||
var destinationQ = worker.DestinationQ.Value;
|
||||
var destinationR = worker.DestinationR.Value;
|
||||
var currentQ = worker.Q;
|
||||
var currentR = worker.R;
|
||||
var nextTick = worker.MovementCompletesAtUtc!.Value;
|
||||
while (nextTick <= now && HexDistance(currentQ, currentR, destinationQ, destinationR) > 1)
|
||||
if (HexDistance(worker.Q, worker.R, destinationQ, destinationR) > 1)
|
||||
{
|
||||
(currentQ, currentR) = NextStepToward(currentQ, currentR, destinationQ, destinationR);
|
||||
nextTick = nextTick.AddMinutes(1);
|
||||
}
|
||||
var nextStep = await NextPeasantStepTowardAsync(username, worker.Q, worker.R, destinationQ, destinationR);
|
||||
if (nextStep is null)
|
||||
{
|
||||
await _units.UpdateOneAsync(
|
||||
x => x.Id == worker.Id,
|
||||
Builders<UnitInstance>.Update
|
||||
.Set(x => x.Status, "Idle")
|
||||
.Unset(x => x.DestinationQ)
|
||||
.Unset(x => x.DestinationR)
|
||||
.Unset(x => x.MovementStartedAtUtc)
|
||||
.Unset(x => x.MovementCompletesAtUtc)
|
||||
.Set(x => x.UpdatedAtUtc, now));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (HexDistance(currentQ, currentR, destinationQ, destinationR) > 1)
|
||||
{
|
||||
await _units.UpdateOneAsync(
|
||||
x => x.Id == worker.Id,
|
||||
Builders<UnitInstance>.Update
|
||||
.Set(x => x.Q, currentQ)
|
||||
.Set(x => x.R, currentR)
|
||||
.Set(x => x.MovementCompletesAtUtc, nextTick)
|
||||
.Set(x => x.Q, nextStep.Value.q)
|
||||
.Set(x => x.R, nextStep.Value.r)
|
||||
.Set(x => x.MovementCompletesAtUtc, now.AddMinutes(1))
|
||||
.Set(x => x.UpdatedAtUtc, now));
|
||||
continue;
|
||||
}
|
||||
@@ -560,7 +566,7 @@ public class LocationService
|
||||
x => x.OwnerUsername == username &&
|
||||
x.Q == destinationQ &&
|
||||
x.R == destinationR &&
|
||||
!string.IsNullOrWhiteSpace(x.BuildingType) &&
|
||||
(x.BuildingType == "LogCamp" || x.BuildingType == "Mine" || x.BuildingType == "Farm") &&
|
||||
x.BuildingStatus != "Building" &&
|
||||
(x.WorkerUnitId == null || x.WorkerUnitId == ""),
|
||||
Builders<Location>.Update
|
||||
@@ -591,13 +597,63 @@ public class LocationService
|
||||
}
|
||||
}
|
||||
|
||||
private static (int q, int r) NextStepToward(int fromQ, int fromR, int toQ, int toR)
|
||||
private async Task<(int q, int r)?> NextPeasantStepTowardAsync(string username, int fromQ, int fromR, int toQ, int toR)
|
||||
{
|
||||
return NeighborCoordinates(fromQ, fromR)
|
||||
.OrderBy(x => HexDistance(x.Q, x.R, toQ, toR))
|
||||
.ThenBy(x => x.Q)
|
||||
.ThenBy(x => x.R)
|
||||
.First();
|
||||
var owned = await _locations.Find(x => x.OwnerUsername == username).ToListAsync();
|
||||
var ownedCoordinates = owned.Select(x => (x.Q, x.R)).ToHashSet();
|
||||
if (!ownedCoordinates.Contains((toQ, toR)))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var start = (fromQ, fromR);
|
||||
var target = (toQ, toR);
|
||||
var queue = new Queue<(int q, int r)>();
|
||||
var previous = new Dictionary<(int q, int r), (int q, int r)>();
|
||||
var visited = new HashSet<(int q, int r)> { start };
|
||||
queue.Enqueue(start);
|
||||
|
||||
while (queue.Count > 0)
|
||||
{
|
||||
var current = queue.Dequeue();
|
||||
if (current == target)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
foreach (var neighbor in NeighborCoordinates(current.q, current.r)
|
||||
.Select(x => (x.Q, x.R))
|
||||
.OrderBy(x => HexDistance(x.Q, x.R, toQ, toR))
|
||||
.ThenBy(x => x.Q)
|
||||
.ThenBy(x => x.R))
|
||||
{
|
||||
if (!ownedCoordinates.Contains(neighbor) || !visited.Add(neighbor))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
previous[neighbor] = current;
|
||||
queue.Enqueue(neighbor);
|
||||
}
|
||||
}
|
||||
|
||||
if (!visited.Contains(target))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var step = target;
|
||||
while (previous.TryGetValue(step, out var before) && before != start)
|
||||
{
|
||||
step = before;
|
||||
}
|
||||
|
||||
return step == start ? target : step;
|
||||
}
|
||||
|
||||
private static bool CanAssignWorkerToBuilding(string? buildingType)
|
||||
{
|
||||
return buildingType == "LogCamp" || buildingType == "Mine" || buildingType == "Farm";
|
||||
}
|
||||
|
||||
public async Task<bool> CanSeeAsync(string username, int q, int r)
|
||||
|
||||
@@ -462,7 +462,7 @@ public class ResourceService
|
||||
.ToListAsync();
|
||||
var persistedUnits = await _units.Find(x =>
|
||||
x.Username == username &&
|
||||
(x.UnitType == ArcherUnitType || x.UnitType == PeasantUnitType))
|
||||
(x.UnitType == ScoutUnitType || x.UnitType == ArcherUnitType || x.UnitType == PeasantUnitType))
|
||||
.ToListAsync();
|
||||
|
||||
var units = completedScouts
|
||||
@@ -511,23 +511,29 @@ public class ResourceService
|
||||
|
||||
var destinationQ = worker.DestinationQ.Value;
|
||||
var destinationR = worker.DestinationR.Value;
|
||||
var currentQ = worker.Q;
|
||||
var currentR = worker.R;
|
||||
var nextTick = worker.MovementCompletesAtUtc!.Value;
|
||||
while (nextTick <= now && HexDistance(currentQ, currentR, destinationQ, destinationR) > 1)
|
||||
if (HexDistance(worker.Q, worker.R, destinationQ, destinationR) > 1)
|
||||
{
|
||||
(currentQ, currentR) = NextStepToward(currentQ, currentR, destinationQ, destinationR);
|
||||
nextTick = nextTick.AddMinutes(1);
|
||||
}
|
||||
var nextStep = await NextPeasantStepTowardAsync(username, worker.Q, worker.R, destinationQ, destinationR);
|
||||
if (nextStep is null)
|
||||
{
|
||||
await _units.UpdateOneAsync(
|
||||
x => x.Id == worker.Id,
|
||||
Builders<UnitInstance>.Update
|
||||
.Set(x => x.Status, "Idle")
|
||||
.Unset(x => x.DestinationQ)
|
||||
.Unset(x => x.DestinationR)
|
||||
.Unset(x => x.MovementStartedAtUtc)
|
||||
.Unset(x => x.MovementCompletesAtUtc)
|
||||
.Set(x => x.UpdatedAtUtc, now));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (HexDistance(currentQ, currentR, destinationQ, destinationR) > 1)
|
||||
{
|
||||
await _units.UpdateOneAsync(
|
||||
x => x.Id == worker.Id,
|
||||
Builders<UnitInstance>.Update
|
||||
.Set(x => x.Q, currentQ)
|
||||
.Set(x => x.R, currentR)
|
||||
.Set(x => x.MovementCompletesAtUtc, nextTick)
|
||||
.Set(x => x.Q, nextStep.Value.q)
|
||||
.Set(x => x.R, nextStep.Value.r)
|
||||
.Set(x => x.MovementCompletesAtUtc, now.AddMinutes(1))
|
||||
.Set(x => x.UpdatedAtUtc, now));
|
||||
continue;
|
||||
}
|
||||
@@ -536,7 +542,7 @@ public class ResourceService
|
||||
x => x.OwnerUsername == username &&
|
||||
x.Q == destinationQ &&
|
||||
x.R == destinationR &&
|
||||
!string.IsNullOrWhiteSpace(x.BuildingType) &&
|
||||
(x.BuildingType == "LogCamp" || x.BuildingType == "Mine" || x.BuildingType == "Farm") &&
|
||||
x.BuildingStatus != "Building" &&
|
||||
(x.WorkerUnitId == null || x.WorkerUnitId == ""),
|
||||
Builders<Location>.Update
|
||||
@@ -561,13 +567,57 @@ public class ResourceService
|
||||
}
|
||||
}
|
||||
|
||||
private static (int q, int r) NextStepToward(int fromQ, int fromR, int toQ, int toR)
|
||||
private async Task<(int q, int r)?> NextPeasantStepTowardAsync(string username, int fromQ, int fromR, int toQ, int toR)
|
||||
{
|
||||
return NeighborCoordinates(fromQ, fromR)
|
||||
.OrderBy(x => HexDistance(x.q, x.r, toQ, toR))
|
||||
.ThenBy(x => x.q)
|
||||
.ThenBy(x => x.r)
|
||||
.First();
|
||||
var owned = await _locations.Find(x => x.OwnerUsername == username).ToListAsync();
|
||||
var ownedCoordinates = owned.Select(x => (x.Q, x.R)).ToHashSet();
|
||||
if (!ownedCoordinates.Contains((toQ, toR)))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var start = (fromQ, fromR);
|
||||
var target = (toQ, toR);
|
||||
var queue = new Queue<(int q, int r)>();
|
||||
var previous = new Dictionary<(int q, int r), (int q, int r)>();
|
||||
var visited = new HashSet<(int q, int r)> { start };
|
||||
queue.Enqueue(start);
|
||||
|
||||
while (queue.Count > 0)
|
||||
{
|
||||
var current = queue.Dequeue();
|
||||
if (current == target)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
foreach (var neighbor in NeighborCoordinates(current.q, current.r)
|
||||
.OrderBy(x => HexDistance(x.q, x.r, toQ, toR))
|
||||
.ThenBy(x => x.q)
|
||||
.ThenBy(x => x.r))
|
||||
{
|
||||
if (!ownedCoordinates.Contains(neighbor) || !visited.Add(neighbor))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
previous[neighbor] = current;
|
||||
queue.Enqueue(neighbor);
|
||||
}
|
||||
}
|
||||
|
||||
if (!visited.Contains(target))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var step = target;
|
||||
while (previous.TryGetValue(step, out var before) && before != start)
|
||||
{
|
||||
step = before;
|
||||
}
|
||||
|
||||
return step == start ? target : step;
|
||||
}
|
||||
|
||||
private static IEnumerable<(int q, int r)> NeighborCoordinates(int q, int r)
|
||||
|
||||
@@ -69,13 +69,14 @@ public class UnitTrainingService
|
||||
public async Task<PlayerUnitsResponse> GetMineAsync(string username)
|
||||
{
|
||||
await CompleteFinishedTrainingAsync(username);
|
||||
await PromoteCompletedScoutsAsync(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();
|
||||
var allUnits = await _units.Find(x => x.Username == username).ToListAsync();
|
||||
var completedScouts = allTraining.Count(x => x.UnitType == ScoutUnitType && x.Status == "Completed");
|
||||
var completedScouts = allUnits.Count(x => x.UnitType == ScoutUnitType && x.Status == "Idle");
|
||||
var completedArchers = allUnits.Count(x => x.UnitType == ArcherUnitType);
|
||||
var completedPeasants = allUnits.Count(x => x.UnitType == PeasantUnitType && x.Status == "Idle");
|
||||
var activeTraining = allTraining
|
||||
@@ -129,6 +130,14 @@ public class UnitTrainingService
|
||||
throw new InvalidOperationException("A town hall is required to train Peasants.");
|
||||
}
|
||||
}
|
||||
else if (normalizedUnitType == ScoutUnitType)
|
||||
{
|
||||
origin = await _locations.Find(x => x.OwnerUsername == username && x.Kind == "Home").FirstOrDefaultAsync();
|
||||
if (origin is null)
|
||||
{
|
||||
throw new InvalidOperationException("A town hall is required to train Scouts.");
|
||||
}
|
||||
}
|
||||
|
||||
var goldCost = normalizedUnitType == ArcherUnitType
|
||||
? await _settings.GetNonNegativeIntAsync(GameSettingsService.ArcherGoldCost, _archerGoldCost)
|
||||
@@ -188,11 +197,6 @@ public class UnitTrainingService
|
||||
}
|
||||
|
||||
var movementDistance = HexDistance(request.FromQ, request.FromR, request.ToQ, request.ToR);
|
||||
if (normalizedUnitType == ArcherUnitType && movementDistance != 1)
|
||||
{
|
||||
throw new InvalidOperationException("Archers can only move to adjacent tiles.");
|
||||
}
|
||||
|
||||
if (normalizedUnitType == ArcherUnitType && !await CanMoveToAsync(username, request.ToQ, request.ToR))
|
||||
{
|
||||
throw new InvalidOperationException("Archers can only move to visible tiles.");
|
||||
@@ -230,7 +234,7 @@ public class UnitTrainingService
|
||||
throw new InvalidOperationException("That squad has no movement remaining this tick.");
|
||||
}
|
||||
|
||||
var movementCompletesAt = now.AddMinutes(Math.Max(1, movementDistance));
|
||||
var movementCompletesAt = now.AddMinutes(1);
|
||||
await _units.UpdateManyAsync(
|
||||
unitFilter,
|
||||
Builders<UnitInstance>.Update
|
||||
@@ -294,23 +298,44 @@ public class UnitTrainingService
|
||||
|
||||
var destinationQ = unit.DestinationQ.Value;
|
||||
var destinationR = unit.DestinationR.Value;
|
||||
var currentQ = unit.Q;
|
||||
var currentR = unit.R;
|
||||
var nextTick = unit.MovementCompletesAtUtc!.Value;
|
||||
while (nextTick <= now && HexDistance(currentQ, currentR, destinationQ, destinationR) > 1)
|
||||
if (unit.UnitType == PeasantUnitType && HexDistance(unit.Q, unit.R, destinationQ, destinationR) > 1)
|
||||
{
|
||||
(currentQ, currentR) = NextStepToward(currentQ, currentR, destinationQ, destinationR);
|
||||
nextTick = nextTick.AddMinutes(1);
|
||||
}
|
||||
var nextStep = await NextPeasantStepTowardAsync(username, unit.Q, unit.R, destinationQ, destinationR);
|
||||
if (nextStep 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.DestinationQ)
|
||||
.Unset(x => x.DestinationR)
|
||||
.Unset(x => x.MovementStartedAtUtc)
|
||||
.Unset(x => x.MovementCompletesAtUtc)
|
||||
.Set(x => x.UpdatedAtUtc, now));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (HexDistance(currentQ, currentR, destinationQ, destinationR) > 1)
|
||||
{
|
||||
await _units.UpdateOneAsync(
|
||||
x => x.Id == unit.Id,
|
||||
Builders<UnitInstance>.Update
|
||||
.Set(x => x.Q, currentQ)
|
||||
.Set(x => x.R, currentR)
|
||||
.Set(x => x.MovementCompletesAtUtc, nextTick)
|
||||
.Set(x => x.Q, nextStep.Value.q)
|
||||
.Set(x => x.R, nextStep.Value.r)
|
||||
.Set(x => x.MovementCompletesAtUtc, now.AddMinutes(1))
|
||||
.Set(x => x.UpdatedAtUtc, now));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (unit.UnitType != PeasantUnitType && HexDistance(unit.Q, unit.R, destinationQ, destinationR) > 1)
|
||||
{
|
||||
var nextStep = NextStepToward(unit.Q, unit.R, destinationQ, destinationR);
|
||||
await _units.UpdateOneAsync(
|
||||
x => x.Id == unit.Id,
|
||||
Builders<UnitInstance>.Update
|
||||
.Set(x => x.Q, nextStep.q)
|
||||
.Set(x => x.R, nextStep.r)
|
||||
.Set(x => x.MovementCompletesAtUtc, now.AddMinutes(1))
|
||||
.Set(x => x.UpdatedAtUtc, now));
|
||||
continue;
|
||||
}
|
||||
@@ -405,6 +430,59 @@ public class UnitTrainingService
|
||||
.AnyAsync();
|
||||
}
|
||||
|
||||
private async Task<(int q, int r)?> NextPeasantStepTowardAsync(string username, int fromQ, int fromR, int toQ, int toR)
|
||||
{
|
||||
var owned = await _locations.Find(x => x.OwnerUsername == username).ToListAsync();
|
||||
var ownedCoordinates = owned.Select(x => (x.Q, x.R)).ToHashSet();
|
||||
if (!ownedCoordinates.Contains((toQ, toR)))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var start = (fromQ, fromR);
|
||||
var target = (toQ, toR);
|
||||
var queue = new Queue<(int q, int r)>();
|
||||
var previous = new Dictionary<(int q, int r), (int q, int r)>();
|
||||
var visited = new HashSet<(int q, int r)> { start };
|
||||
queue.Enqueue(start);
|
||||
|
||||
while (queue.Count > 0)
|
||||
{
|
||||
var current = queue.Dequeue();
|
||||
if (current == target)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
foreach (var neighbor in NeighborCoordinates(current.q, current.r)
|
||||
.OrderBy(x => HexDistance(x.q, x.r, toQ, toR))
|
||||
.ThenBy(x => x.q)
|
||||
.ThenBy(x => x.r))
|
||||
{
|
||||
if (!ownedCoordinates.Contains(neighbor) || !visited.Add(neighbor))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
previous[neighbor] = current;
|
||||
queue.Enqueue(neighbor);
|
||||
}
|
||||
}
|
||||
|
||||
if (!visited.Contains(target))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var step = target;
|
||||
while (previous.TryGetValue(step, out var before) && before != start)
|
||||
{
|
||||
step = before;
|
||||
}
|
||||
|
||||
return step == start ? target : step;
|
||||
}
|
||||
|
||||
private async Task ClaimTargetIfEmptyAsync(string username, int q, int r, DateTime now)
|
||||
{
|
||||
var hasOtherUnits = await _units.Find(x => x.Username != username && x.Q == q && x.R == r).AnyAsync();
|
||||
@@ -492,6 +570,18 @@ public class UnitTrainingService
|
||||
public async Task<bool> TryConsumeCompletedScoutAsync(string username)
|
||||
{
|
||||
await CompleteFinishedTrainingAsync(username);
|
||||
await PromoteCompletedScoutsAsync(username);
|
||||
|
||||
var consumedUnit = await _units.FindOneAndDeleteAsync(
|
||||
x => x.Username == username && x.UnitType == ScoutUnitType && x.Status == "Idle",
|
||||
new FindOneAndDeleteOptions<UnitInstance>
|
||||
{
|
||||
Sort = Builders<UnitInstance>.Sort.Ascending(x => x.CreatedAtUtc)
|
||||
});
|
||||
if (consumedUnit is not null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
var consumed = await _training.FindOneAndDeleteAsync(
|
||||
x => x.Username == username && x.UnitType == ScoutUnitType && x.Status == "Completed",
|
||||
@@ -506,7 +596,8 @@ public class UnitTrainingService
|
||||
public async Task<bool> HasCompletedScoutAsync(string username)
|
||||
{
|
||||
await CompleteFinishedTrainingAsync(username);
|
||||
return await _training.Find(x => x.Username == username && x.UnitType == ScoutUnitType && x.Status == "Completed").AnyAsync();
|
||||
await PromoteCompletedScoutsAsync(username);
|
||||
return await _units.Find(x => x.Username == username && x.UnitType == ScoutUnitType && x.Status == "Idle").AnyAsync();
|
||||
}
|
||||
|
||||
private async Task CompleteFinishedTrainingAsync(string username)
|
||||
@@ -533,7 +624,7 @@ public class UnitTrainingService
|
||||
ReturnDocument = ReturnDocument.After
|
||||
});
|
||||
|
||||
if (completed is null || (completed.UnitType != ArcherUnitType && completed.UnitType != PeasantUnitType))
|
||||
if (completed is null || (completed.UnitType != ArcherUnitType && completed.UnitType != PeasantUnitType && completed.UnitType != ScoutUnitType))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@@ -557,6 +648,14 @@ public class UnitTrainingService
|
||||
try
|
||||
{
|
||||
await _units.InsertOneAsync(unit);
|
||||
if (completed.UnitType == ScoutUnitType)
|
||||
{
|
||||
await _training.UpdateOneAsync(
|
||||
x => x.Id == completed.Id,
|
||||
Builders<UnitTraining>.Update
|
||||
.Set(x => x.Status, "Consumed")
|
||||
.Set(x => x.UpdatedAtUtc, now));
|
||||
}
|
||||
}
|
||||
catch (MongoWriteException)
|
||||
{
|
||||
@@ -564,6 +663,58 @@ public class UnitTrainingService
|
||||
}
|
||||
}
|
||||
|
||||
private async Task PromoteCompletedScoutsAsync(string username)
|
||||
{
|
||||
var now = DateTime.UtcNow;
|
||||
var completedScouts = await _training.Find(x =>
|
||||
x.Username == username &&
|
||||
x.UnitType == ScoutUnitType &&
|
||||
x.Status == "Completed")
|
||||
.ToListAsync();
|
||||
if (completedScouts.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var home = await _locations.Find(x => x.OwnerUsername == username && x.Kind == "Home").FirstOrDefaultAsync();
|
||||
var movementPerTick = await _settings.GetIntAsync(GameSettingsService.UnitMovementPerTick, _unitMovementPerTick);
|
||||
foreach (var scout in completedScouts)
|
||||
{
|
||||
var existing = await _units.Find(x => x.SourceTrainingId == scout.Id).AnyAsync();
|
||||
if (!existing)
|
||||
{
|
||||
var unit = new UnitInstance
|
||||
{
|
||||
Username = scout.Username,
|
||||
UnitType = ScoutUnitType,
|
||||
Q = scout.OriginQ ?? home?.Q ?? 0,
|
||||
R = scout.OriginR ?? home?.R ?? 0,
|
||||
Status = "Idle",
|
||||
MovementPerTick = movementPerTick,
|
||||
MovementRemaining = movementPerTick,
|
||||
LastMovementRefillAtUtc = now,
|
||||
SourceTrainingId = scout.Id,
|
||||
CreatedAtUtc = now,
|
||||
UpdatedAtUtc = now
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
await _units.InsertOneAsync(unit);
|
||||
}
|
||||
catch (MongoWriteException)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
await _training.UpdateOneAsync(
|
||||
x => x.Id == scout.Id,
|
||||
Builders<UnitTraining>.Update
|
||||
.Set(x => x.Status, "Consumed")
|
||||
.Set(x => x.UpdatedAtUtc, now));
|
||||
}
|
||||
}
|
||||
|
||||
private static string? NormalizeUnitType(string unitType)
|
||||
{
|
||||
var trimmed = unitType.Trim();
|
||||
|
||||
Reference in New Issue
Block a user