Updating peasants
This commit is contained in:
@@ -6,6 +6,7 @@ namespace LocationsApi.Services;
|
||||
public class ResourceService
|
||||
{
|
||||
private readonly IMongoCollection<PlayerResources> _resources;
|
||||
private readonly IMongoCollection<Location> _locations;
|
||||
private readonly GameSettingsService _settings;
|
||||
private readonly int _startingGold;
|
||||
private readonly int _headquartersGoldPerMinute;
|
||||
@@ -13,6 +14,7 @@ public class ResourceService
|
||||
private readonly int _townHallWoodCapacity;
|
||||
private readonly int _townHallOreCapacity;
|
||||
private readonly int _townHallFoodCapacity;
|
||||
private readonly int _productionBuildingResourceCapacity;
|
||||
|
||||
public ResourceService(IConfiguration cfg, GameSettingsService settings)
|
||||
{
|
||||
@@ -21,6 +23,7 @@ public class ResourceService
|
||||
var client = new MongoClient(connectionString);
|
||||
var database = client.GetDatabase(databaseName);
|
||||
_resources = database.GetCollection<PlayerResources>("PlayerResources");
|
||||
_locations = database.GetCollection<Location>("Locations");
|
||||
_settings = settings;
|
||||
_startingGold = int.TryParse(cfg["Resources:StartingGold"], out var startingGold) ? Math.Max(0, startingGold) : 100;
|
||||
_headquartersGoldPerMinute = int.TryParse(cfg["Resources:HeadquartersGoldPerMinute"], out var goldPerMinute)
|
||||
@@ -38,6 +41,9 @@ public class ResourceService
|
||||
_townHallFoodCapacity = int.TryParse(cfg["Resources:TownHallFoodCapacity"], out var foodCapacity)
|
||||
? Math.Max(0, foodCapacity)
|
||||
: 100;
|
||||
_productionBuildingResourceCapacity = int.TryParse(cfg["Buildings:ProductionBuildingResourceCapacity"], out var productionBuildingResourceCapacity)
|
||||
? Math.Max(0, productionBuildingResourceCapacity)
|
||||
: 10;
|
||||
|
||||
_resources.Indexes.CreateOne(new CreateIndexModel<PlayerResources>(
|
||||
Builders<PlayerResources>.IndexKeys.Ascending(x => x.Username),
|
||||
@@ -85,7 +91,8 @@ public class ResourceService
|
||||
|
||||
public async Task<PlayerResources> GetAsync(string username)
|
||||
{
|
||||
return await EnsureAsync(username);
|
||||
var resources = await EnsureAsync(username);
|
||||
return await ApplyProductionBuildingDeliveryAsync(resources);
|
||||
}
|
||||
|
||||
public async Task<bool> TrySpendGoldAsync(string username, int amount)
|
||||
@@ -207,6 +214,33 @@ public class ResourceService
|
||||
await _resources.UpdateOneAsync(x => x.Username == username, update);
|
||||
}
|
||||
|
||||
public async Task SetBuildingGenerationAsync(string username, int woodPerMinute, int orePerMinute, int foodPerMinute)
|
||||
{
|
||||
await EnsureAsync(username);
|
||||
var now = DateTime.UtcNow;
|
||||
var update = Builders<PlayerResources>.Update
|
||||
.Set(x => x.WoodPerMinute, Math.Max(0, woodPerMinute))
|
||||
.Set(x => x.OrePerMinute, Math.Max(0, orePerMinute))
|
||||
.Set(x => x.FoodPerMinute, Math.Max(0, foodPerMinute))
|
||||
.Set(x => x.UpdatedAtUtc, now);
|
||||
|
||||
if (woodPerMinute > 0)
|
||||
{
|
||||
update = update.Set(x => x.LastWoodGeneratedAtUtc, now);
|
||||
}
|
||||
if (orePerMinute > 0)
|
||||
{
|
||||
update = update.Set(x => x.LastOreGeneratedAtUtc, now);
|
||||
}
|
||||
if (foodPerMinute > 0)
|
||||
{
|
||||
update = update.Set(x => x.LastFoodGeneratedAtUtc, now);
|
||||
}
|
||||
|
||||
await _resources.UpdateOneAsync(x => x.Username == username, update);
|
||||
}
|
||||
|
||||
|
||||
private async Task<PlayerResources> ApplyResourceGenerationAsync(PlayerResources resources)
|
||||
{
|
||||
var now = DateTime.UtcNow;
|
||||
@@ -218,22 +252,13 @@ public class ResourceService
|
||||
var goldElapsedMinutes = goldPerMinute <= 0
|
||||
? 0
|
||||
: (int)Math.Floor((now - resources.LastGoldGeneratedAtUtc).TotalMinutes);
|
||||
var woodElapsedMinutes = resources.WoodPerMinute <= 0 || resources.LastWoodGeneratedAtUtc.Year < 2000
|
||||
? 0
|
||||
: (int)Math.Floor((now - resources.LastWoodGeneratedAtUtc).TotalMinutes);
|
||||
var oreElapsedMinutes = resources.OrePerMinute <= 0 || resources.LastOreGeneratedAtUtc.Year < 2000
|
||||
? 0
|
||||
: (int)Math.Floor((now - resources.LastOreGeneratedAtUtc).TotalMinutes);
|
||||
var foodElapsedMinutes = resources.FoodPerMinute <= 0 || resources.LastFoodGeneratedAtUtc.Year < 2000
|
||||
? 0
|
||||
: (int)Math.Floor((now - resources.LastFoodGeneratedAtUtc).TotalMinutes);
|
||||
var cappedGold = Math.Min(resources.Gold, goldCapacity);
|
||||
var cappedWood = Math.Min(resources.Wood, woodCapacity);
|
||||
var cappedOre = Math.Min(resources.Ore, oreCapacity);
|
||||
var cappedFood = Math.Min(resources.Food, foodCapacity);
|
||||
var isOverCapacity = resources.Gold != cappedGold || resources.Wood != cappedWood || resources.Ore != cappedOre || resources.Food != cappedFood;
|
||||
|
||||
if (goldElapsedMinutes <= 0 && woodElapsedMinutes <= 0 && oreElapsedMinutes <= 0 && foodElapsedMinutes <= 0 && !isOverCapacity)
|
||||
if (goldElapsedMinutes <= 0 && !isOverCapacity)
|
||||
{
|
||||
return resources;
|
||||
}
|
||||
@@ -263,30 +288,6 @@ public class ResourceService
|
||||
.Set(x => x.LastGoldGeneratedAtUtc, resources.LastGoldGeneratedAtUtc.AddMinutes(goldElapsedMinutes));
|
||||
}
|
||||
|
||||
if (woodElapsedMinutes > 0)
|
||||
{
|
||||
var generatedWood = Math.Min(woodCapacity, cappedWood + (woodElapsedMinutes * resources.WoodPerMinute));
|
||||
update = update
|
||||
.Set(x => x.Wood, generatedWood)
|
||||
.Set(x => x.LastWoodGeneratedAtUtc, resources.LastWoodGeneratedAtUtc.AddMinutes(woodElapsedMinutes));
|
||||
}
|
||||
|
||||
if (oreElapsedMinutes > 0)
|
||||
{
|
||||
var generatedOre = Math.Min(oreCapacity, cappedOre + (oreElapsedMinutes * resources.OrePerMinute));
|
||||
update = update
|
||||
.Set(x => x.Ore, generatedOre)
|
||||
.Set(x => x.LastOreGeneratedAtUtc, resources.LastOreGeneratedAtUtc.AddMinutes(oreElapsedMinutes));
|
||||
}
|
||||
|
||||
if (foodElapsedMinutes > 0)
|
||||
{
|
||||
var generatedFood = Math.Min(foodCapacity, cappedFood + (foodElapsedMinutes * resources.FoodPerMinute));
|
||||
update = update
|
||||
.Set(x => x.Food, generatedFood)
|
||||
.Set(x => x.LastFoodGeneratedAtUtc, resources.LastFoodGeneratedAtUtc.AddMinutes(foodElapsedMinutes));
|
||||
}
|
||||
|
||||
return await _resources.FindOneAndUpdateAsync(
|
||||
x => x.Username == resources.Username,
|
||||
update,
|
||||
@@ -295,4 +296,85 @@ public class ResourceService
|
||||
ReturnDocument = ReturnDocument.After
|
||||
});
|
||||
}
|
||||
|
||||
private async Task<PlayerResources> ApplyProductionBuildingDeliveryAsync(PlayerResources resources)
|
||||
{
|
||||
var now = DateTime.UtcNow;
|
||||
var woodCapacity = await _settings.GetNonNegativeIntAsync(GameSettingsService.TownHallWoodCapacity, _townHallWoodCapacity);
|
||||
var oreCapacity = await _settings.GetNonNegativeIntAsync(GameSettingsService.TownHallOreCapacity, _townHallOreCapacity);
|
||||
var foodCapacity = await _settings.GetNonNegativeIntAsync(GameSettingsService.TownHallFoodCapacity, _townHallFoodCapacity);
|
||||
var buildingCapacity = await _settings.GetNonNegativeIntAsync(GameSettingsService.ProductionBuildingResourceCapacity, _productionBuildingResourceCapacity);
|
||||
var logCampWoodPerMinute = await _settings.GetNonNegativeIntAsync(GameSettingsService.LogCampWoodPerMinute, 5);
|
||||
var mineOrePerMinute = await _settings.GetNonNegativeIntAsync(GameSettingsService.MineOrePerMinute, 5);
|
||||
var farmFoodPerMinute = await _settings.GetNonNegativeIntAsync(GameSettingsService.FarmFoodPerMinute, 5);
|
||||
|
||||
var buildings = await _locations.Find(x =>
|
||||
x.OwnerUsername == resources.Username &&
|
||||
!string.IsNullOrWhiteSpace(x.WorkerUnitId) &&
|
||||
(x.BuildingStatus == "Built" || x.BuildingStatus == null || x.BuildingStatus == "") &&
|
||||
(x.BuildingType == "LogCamp" || x.BuildingType == "Mine" || x.BuildingType == "Farm"))
|
||||
.ToListAsync();
|
||||
|
||||
var wood = Math.Min(resources.Wood, woodCapacity);
|
||||
var ore = Math.Min(resources.Ore, oreCapacity);
|
||||
var food = Math.Min(resources.Food, foodCapacity);
|
||||
|
||||
foreach (var building in buildings)
|
||||
{
|
||||
var rate = building.BuildingType switch
|
||||
{
|
||||
"LogCamp" => logCampWoodPerMinute,
|
||||
"Mine" => mineOrePerMinute,
|
||||
"Farm" => farmFoodPerMinute,
|
||||
_ => 0
|
||||
};
|
||||
var lastGenerated = building.LastResourceGeneratedAtUtc ?? building.BuildingBuiltAtUtc ?? now;
|
||||
var elapsedMinutes = rate <= 0 ? 0 : (int)Math.Floor((now - lastGenerated).TotalMinutes);
|
||||
var stored = Math.Min(buildingCapacity, Math.Max(0, building.StoredResourceAmount) + (elapsedMinutes * rate));
|
||||
|
||||
var delivered = 0;
|
||||
if (building.BuildingType == "LogCamp")
|
||||
{
|
||||
delivered = Math.Min(stored, Math.Max(0, woodCapacity - wood));
|
||||
wood += delivered;
|
||||
}
|
||||
else if (building.BuildingType == "Mine")
|
||||
{
|
||||
delivered = Math.Min(stored, Math.Max(0, oreCapacity - ore));
|
||||
ore += delivered;
|
||||
}
|
||||
else if (building.BuildingType == "Farm")
|
||||
{
|
||||
delivered = Math.Min(stored, Math.Max(0, foodCapacity - food));
|
||||
food += delivered;
|
||||
}
|
||||
|
||||
var update = Builders<Location>.Update
|
||||
.Set(x => x.StoredResourceAmount, stored - delivered)
|
||||
.Set(x => x.StoredResourceCapacity, buildingCapacity)
|
||||
.Set(x => x.UpdatedAtUtc, now);
|
||||
|
||||
if (elapsedMinutes > 0 || building.LastResourceGeneratedAtUtc is null)
|
||||
{
|
||||
update = update.Set(x => x.LastResourceGeneratedAtUtc, lastGenerated.AddMinutes(elapsedMinutes));
|
||||
}
|
||||
|
||||
await _locations.UpdateOneAsync(x => x.Id == building.Id, update);
|
||||
}
|
||||
|
||||
return await _resources.FindOneAndUpdateAsync(
|
||||
x => x.Username == resources.Username,
|
||||
Builders<PlayerResources>.Update
|
||||
.Set(x => x.Wood, wood)
|
||||
.Set(x => x.Ore, ore)
|
||||
.Set(x => x.Food, food)
|
||||
.Set(x => x.WoodCapacity, woodCapacity)
|
||||
.Set(x => x.OreCapacity, oreCapacity)
|
||||
.Set(x => x.FoodCapacity, foodCapacity)
|
||||
.Set(x => x.UpdatedAtUtc, now),
|
||||
new FindOneAndUpdateOptions<PlayerResources>
|
||||
{
|
||||
ReturnDocument = ReturnDocument.After
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user