添加项目文件。

This commit is contained in:
2026-10-12 16:22:04 +08:00
parent 7c68a0ca0a
commit aad11be43d
1000 changed files with 120807 additions and 0 deletions
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,10 @@
namespace FishGameService.Services;
public static class KillAnnouncePolicy
{
public static bool ShouldAnnounce(long gold, long configuredMinGold)
{
var minGold = configuredMinGold > 0 ? configuredMinGold : 10_000_000L;
return gold >= minGold;
}
}
@@ -0,0 +1,138 @@
using CommonDomain;
using DotNetCore.CAP;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using MongoRepository;
using RedisService;
namespace FishGameService.Services;
public class RobotKillAnnounceService : BackgroundService
{
private readonly ILogger<RobotKillAnnounceService> _logger;
private readonly IServiceScopeFactory _scopeFactory;
private readonly ICapPublisher _capPublisher;
private static readonly Random _random = new();
private const int MinimumAnnounceIntervalSeconds = 30;
private static readonly TimeSpan BotProfileCacheDuration = TimeSpan.FromMinutes(5);
private List<BotProfileEntity> _botProfiles = new();
private DateTime _botProfilesLastFetch = DateTime.MinValue;
private string? _lastConfigState;
private DateTime _lastConfigLogUtc = DateTime.MinValue;
public RobotKillAnnounceService(
ILogger<RobotKillAnnounceService> logger,
IServiceScopeFactory scopeFactory,
ICapPublisher capPublisher)
{
_logger = logger;
_scopeFactory = scopeFactory;
_capPublisher = capPublisher;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
var instanceId = Environment.GetEnvironmentVariable("INSTANCE_ID");
if (!string.IsNullOrWhiteSpace(instanceId) && instanceId != "1" && instanceId != "default")
{
return;
}
await Task.Delay(TimeSpan.FromSeconds(10), stoppingToken);
while (!stoppingToken.IsCancellationRequested)
{
try
{
using var scope = _scopeFactory.CreateScope();
var redisService = scope.ServiceProvider.GetRequiredService<IRedisService>();
var botRepo = scope.ServiceProvider.GetRequiredService<IMongoBaseRepository<BotProfileEntity>>();
var gameConfig = redisService.GetGameConfig();
var cfg = gameConfig?.RobotKillConfig;
var configState = cfg == null ? "Missing" : !cfg.IsEnabled ? "Disabled" : cfg.Scenes == null || cfg.Scenes.Count == 0 ? "NoScenes" : "Enabled";
if (configState != _lastConfigState || DateTime.UtcNow - _lastConfigLogUtc >= TimeSpan.FromMinutes(5))
{
_lastConfigState = configState;
_lastConfigLogUtc = DateTime.UtcNow;
}
if (cfg != null && cfg.IsEnabled && cfg.Scenes != null && cfg.Scenes.Count > 0)
{
var scene = PickSceneByWeight(cfg.Scenes);
if (scene != null)
{
var botProfiles = await GetBotProfilesAsync(botRepo);
var multiplier = scene.MultiplierMin >= scene.MultiplierMax
? scene.MultiplierMin
: _random.Next(scene.MultiplierMin, scene.MultiplierMax + 1);
var jackpot = scene.JackpotMin >= scene.JackpotMax
? scene.JackpotMin
: _random.NextInt64(scene.JackpotMin, scene.JackpotMax + 1);
var botName = GenerateBotName(botProfiles);
if (KillAnnouncePolicy.ShouldAnnounce(jackpot, gameConfig?.KillConfig?.GlobalAnnounceMinGold ?? 0))
{
_capPublisher.Publish(TopicKeys.全局击杀公告, new KillAnnounceParam
{
UserName = botName,
GameTypeName = scene.GameName,
RoomName = scene.LevelName,
FishName = scene.FishName,
Multiple = multiplier,
Gold = jackpot,
Timestamp = DateTimeOffset.UtcNow.ToUnixTimeSeconds()
});
}
}
}
var configuredInterval = cfg?.IntervalSeconds > 0 ? cfg.IntervalSeconds : MinimumAnnounceIntervalSeconds;
var interval = Math.Max(configuredInterval, MinimumAnnounceIntervalSeconds) * 1000;
await Task.Delay(interval, stoppingToken);
}
catch (OperationCanceledException) { break; }
catch (Exception ex)
{
_logger.LogError(ex, "RobotKillAnnounceService 执行异常");
await Task.Delay(5000, stoppingToken);
}
}
}
private async Task<List<BotProfileEntity>> GetBotProfilesAsync(IMongoBaseRepository<BotProfileEntity> botRepo)
{
var now = DateTime.UtcNow;
if (_botProfiles.Count > 0 && now - _botProfilesLastFetch < BotProfileCacheDuration)
return _botProfiles;
var profiles = await botRepo.FilterByAsync(b => true) ?? new List<BotProfileEntity>();
_botProfiles = profiles;
_botProfilesLastFetch = now;
return _botProfiles;
}
private RobotKillScene? PickSceneByWeight(List<RobotKillScene> scenes)
{
var totalWeight = scenes.Sum(s => s.Weight);
if (totalWeight <= 0) return null;
var roll = _random.Next(totalWeight);
var accumulated = 0;
foreach (var scene in scenes)
{
accumulated += scene.Weight;
if (roll < accumulated) return scene;
}
return scenes.LastOrDefault();
}
private static string GenerateBotName(List<BotProfileEntity>? botProfiles)
{
if (botProfiles != null && botProfiles.Count > 0)
return botProfiles[_random.Next(botProfiles.Count)].Name;
return $"玩家{_random.Next(10000, 99999)}";
}
}