adding timer cfgs

This commit is contained in:
hz
2026-05-18 20:53:29 -05:00
parent bf75f02dbb
commit 984a82bf48
12 changed files with 177 additions and 14 deletions
@@ -0,0 +1,44 @@
using LocationsApi.Models;
using MongoDB.Driver;
namespace LocationsApi.Services;
public class GameSettingsService
{
public const string ScoutTrainingSeconds = "ScoutTrainingSeconds";
public const string LogCampBuildSeconds = "LogCampBuildSeconds";
private readonly IMongoCollection<GameSetting> _settings;
public GameSettingsService(IConfiguration cfg)
{
var connectionString = cfg["MongoDB:ConnectionString"] ?? "mongodb://127.0.0.1:27017";
var databaseName = cfg["MongoDB:DatabaseName"] ?? "territory-autobattler";
var client = new MongoClient(connectionString);
var database = client.GetDatabase(databaseName);
_settings = database.GetCollection<GameSetting>("GameSettings");
_settings.Indexes.CreateOne(new CreateIndexModel<GameSetting>(
Builders<GameSetting>.IndexKeys.Ascending(x => x.Key),
new CreateIndexOptions { Unique = true }));
}
public async Task<int> GetIntAsync(string key, int defaultValue)
{
var now = DateTime.UtcNow;
var setting = await _settings.FindOneAndUpdateAsync(
x => x.Key == key,
Builders<GameSetting>.Update
.SetOnInsert(x => x.Key, key)
.SetOnInsert(x => x.IntValue, defaultValue)
.SetOnInsert(x => x.CreatedAtUtc, now)
.Set(x => x.UpdatedAtUtc, now),
new FindOneAndUpdateOptions<GameSetting>
{
IsUpsert = true,
ReturnDocument = ReturnDocument.After
});
return Math.Max(1, setting.IntValue);
}
}
@@ -7,12 +7,14 @@ public class LocationService
{
private readonly IMongoCollection<Location> _locations;
private readonly ResourceService _resources;
private readonly GameSettingsService _settings;
private readonly int _homeMinDistance;
private readonly int _homeSearchRadius;
private readonly int _visibilityDepth;
private readonly int _logCampWoodPerMinute;
private readonly int _defaultLogCampBuildSeconds;
public LocationService(IConfiguration cfg, ResourceService resources)
public LocationService(IConfiguration cfg, ResourceService resources, GameSettingsService settings)
{
var connectionString = cfg["MongoDB:ConnectionString"] ?? "mongodb://127.0.0.1:27017";
var databaseName = cfg["MongoDB:DatabaseName"] ?? "territory-autobattler";
@@ -20,12 +22,16 @@ public class LocationService
var database = client.GetDatabase(databaseName);
_locations = database.GetCollection<Location>("Locations");
_resources = resources;
_settings = settings;
_homeMinDistance = int.TryParse(cfg["World:HomeMinDistance"], out var minDistance) ? Math.Max(1, minDistance) : 8;
_homeSearchRadius = int.TryParse(cfg["World:HomeSearchRadius"], out var searchRadius) ? Math.Max(_homeMinDistance, searchRadius) : 80;
_visibilityDepth = int.TryParse(cfg["World:VisibilityDepth"], out var visibilityDepth) ? Math.Max(0, visibilityDepth) : 3;
_logCampWoodPerMinute = int.TryParse(cfg["Buildings:LogCampWoodPerMinute"], out var logCampWoodPerMinute)
? Math.Max(1, logCampWoodPerMinute)
: 5;
_defaultLogCampBuildSeconds = int.TryParse(cfg["Buildings:LogCampBuildSeconds"], out var logCampBuildSeconds)
? Math.Max(1, logCampBuildSeconds)
: 60;
var coordinateIndex = Builders<Location>.IndexKeys
.Ascending(x => x.Q)
@@ -139,10 +145,15 @@ public class LocationService
throw new InvalidOperationException("Log Camps can only be built on Forest territory.");
}
await CompleteFinishedBuildingsAsync(username);
var now = DateTime.UtcNow;
var buildSeconds = await _settings.GetIntAsync(GameSettingsService.LogCampBuildSeconds, _defaultLogCampBuildSeconds);
var update = Builders<Location>.Update
.Set(x => x.BuildingType, "LogCamp")
.Set(x => x.BuildingBuiltAtUtc, now)
.Set(x => x.BuildingStatus, "Building")
.Set(x => x.BuildingStartedAtUtc, now)
.Set(x => x.BuildingCompletesAtUtc, now.AddSeconds(buildSeconds))
.Set(x => x.UpdatedAtUtc, now);
var updated = await _locations.FindOneAndUpdateAsync(
@@ -158,10 +169,41 @@ public class LocationService
throw new InvalidOperationException("This location already has a building.");
}
await _resources.AddWoodGenerationAsync(username, _logCampWoodPerMinute);
return updated;
}
public async Task CompleteFinishedBuildingsAsync(string username)
{
var now = DateTime.UtcNow;
var readyBuildings = await _locations.Find(x =>
x.OwnerUsername == username &&
x.BuildingType == "LogCamp" &&
x.BuildingStatus == "Building" &&
x.BuildingCompletesAtUtc <= now)
.ToListAsync();
foreach (var building in readyBuildings)
{
var update = Builders<Location>.Update
.Set(x => x.BuildingStatus, "Built")
.Set(x => x.BuildingBuiltAtUtc, now)
.Set(x => x.UpdatedAtUtc, now);
var updated = await _locations.FindOneAndUpdateAsync(
x => x.Id == building.Id && x.BuildingStatus == "Building",
update,
new FindOneAndUpdateOptions<Location>
{
ReturnDocument = ReturnDocument.After
});
if (updated is not null)
{
await _resources.AddWoodGenerationAsync(username, _logCampWoodPerMinute);
}
}
}
public async Task<Location?> GetHomeAsync(string username) =>
await _locations.Find(x => x.OwnerUsername == username && x.Kind == "Home").FirstOrDefaultAsync();
@@ -204,6 +246,8 @@ public class LocationService
public async Task<List<LocationResponse>> GetVisibleAsync(string username, int? visibilityDepth = null)
{
await CompleteFinishedBuildingsAsync(username);
var ownedLocations = await _locations.Find(x => x.OwnerUsername == username).ToListAsync();
if (ownedLocations.Count == 0)
{
@@ -9,10 +9,11 @@ public class UnitTrainingService
private readonly IMongoCollection<UnitTraining> _training;
private readonly ResourceService _resources;
private readonly GameSettingsService _settings;
private readonly int _scoutGoldCost;
private readonly int _scoutTrainingSeconds;
private readonly int _defaultScoutTrainingSeconds;
public UnitTrainingService(IConfiguration cfg, ResourceService resources)
public UnitTrainingService(IConfiguration cfg, ResourceService resources, GameSettingsService settings)
{
var connectionString = cfg["MongoDB:ConnectionString"] ?? "mongodb://127.0.0.1:27017";
var databaseName = cfg["MongoDB:DatabaseName"] ?? "territory-autobattler";
@@ -20,8 +21,9 @@ public class UnitTrainingService
var database = client.GetDatabase(databaseName);
_training = database.GetCollection<UnitTraining>("UnitTraining");
_resources = resources;
_settings = settings;
_scoutGoldCost = int.TryParse(cfg["Units:ScoutGoldCost"], out var scoutGoldCost) ? Math.Max(0, scoutGoldCost) : 50;
_scoutTrainingSeconds = int.TryParse(cfg["Units:ScoutTrainingSeconds"], out var scoutTrainingSeconds)
_defaultScoutTrainingSeconds = int.TryParse(cfg["Units:ScoutTrainingSeconds"], out var scoutTrainingSeconds)
? Math.Max(1, scoutTrainingSeconds)
: 60;
@@ -62,6 +64,7 @@ public class UnitTrainingService
}
var now = DateTime.UtcNow;
var scoutTrainingSeconds = await _settings.GetIntAsync(GameSettingsService.ScoutTrainingSeconds, _defaultScoutTrainingSeconds);
var training = new UnitTraining
{
Username = username,
@@ -69,7 +72,7 @@ public class UnitTrainingService
GoldCost = _scoutGoldCost,
Status = "Training",
StartedAtUtc = now,
CompletesAtUtc = now.AddSeconds(_scoutTrainingSeconds),
CompletesAtUtc = now.AddSeconds(scoutTrainingSeconds),
CreatedAtUtc = now,
UpdatedAtUtc = now
};