355 lines
17 KiB
C#
355 lines
17 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
using AutoMapper;
|
|
using CommonDomain;
|
|
using CommonDomain.BaseModel;
|
|
using CommonDomain.Enum;
|
|
using DotNetCore.CAP;
|
|
using Microsoft.Extensions.Logging;
|
|
using MongoRepository;
|
|
using NewLife;
|
|
using RedisService;
|
|
using RedisService.Param;
|
|
|
|
namespace AdminService.GameConfigs
|
|
{
|
|
public class GameConfigService : IGameConfigService
|
|
{
|
|
private readonly IMongoBaseRepository<GameConfig> _mongo;
|
|
private readonly IMapper _mapper;
|
|
private IRedisService _redis;
|
|
private readonly ICapPublisher _capPublisher;
|
|
private readonly IMongoBaseRepository<BotProfileEntity> _botProfileRepo;
|
|
private readonly IMongoBaseRepository<EmptyRoomRateConfig> _emptyRoomRateRepo;
|
|
private readonly ILogger<GameConfigService> _logger;
|
|
|
|
public GameConfigService(IMongoBaseRepository<GameConfig> mongo, IMapper mapper, IRedisService redis, ICapPublisher capPublisher, IMongoBaseRepository<BotProfileEntity> botProfileRepo, IMongoBaseRepository<EmptyRoomRateConfig> emptyRoomRateRepo, ILogger<GameConfigService> logger)
|
|
{
|
|
_mongo = mongo;
|
|
_mapper = mapper;
|
|
_redis = redis;
|
|
_capPublisher = capPublisher;
|
|
_botProfileRepo = botProfileRepo;
|
|
_emptyRoomRateRepo = emptyRoomRateRepo;
|
|
_logger = logger;
|
|
}
|
|
|
|
public async Task<GameConfig> Get()
|
|
{
|
|
var gameConfig = _redis.GetGameConfig();
|
|
if (gameConfig == null)
|
|
{
|
|
gameConfig = await _mongo.FindOneAsync(c => true);
|
|
if (gameConfig != null)
|
|
_redis.SetGameConfig(gameConfig);
|
|
}
|
|
return gameConfig;
|
|
}
|
|
public async Task<(bool isok, string msg)> Update(GameConfig gameConfig)
|
|
{
|
|
NormalizeFishReferences(gameConfig);
|
|
var operationId = Guid.NewGuid().ToString("N");
|
|
var startedAt = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
|
|
bool isadd = false;
|
|
var model = await Get();
|
|
if (model == null)
|
|
{
|
|
isadd = true;
|
|
gameConfig.Id = Guid.NewGuid().ToString("N");
|
|
}
|
|
else
|
|
{
|
|
gameConfig.Id = model.Id;
|
|
}
|
|
|
|
var saveResult = isadd
|
|
? await _mongo.InsertOneAsync(gameConfig)
|
|
: await _mongo.ReplaceOneAsync(gameConfig);
|
|
if (!saveResult.ok)
|
|
{
|
|
|
|
return saveResult;
|
|
}
|
|
|
|
_redis.SetGameConfig(gameConfig);
|
|
|
|
|
|
var killConfig = new FishingKillConfig
|
|
{
|
|
FishTypeConfigs = gameConfig.FishTypeConfigs?.Select(f => new FishTypeBriefConfig
|
|
{
|
|
FishNumber = f.FishNumber,
|
|
FishName = f.FishName,
|
|
FishType = f.FishType,
|
|
FishScore = f.FishScore,
|
|
KillWeight = f.KillWeight
|
|
}).ToList(),
|
|
KillConfig = gameConfig.KillConfig,
|
|
BossConfigs = gameConfig.BossConfigs,
|
|
BossDropConfig = gameConfig.BossDropConfig,
|
|
BattleOrderIsOpen = _redis.GetActivityConfig()?.BattleOrderConfig?.IsOpen ?? false
|
|
};
|
|
_redis.SetFishingKillConfig(killConfig);
|
|
|
|
try
|
|
{
|
|
var fishSpawnJson = FishSpawnExtractor.ExtractToJson(gameConfig);
|
|
_redis.SetFishSpawnConfig(fishSpawnJson);
|
|
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "[FishSpawn] 出鱼配置提取失败");
|
|
}
|
|
|
|
try
|
|
{
|
|
var publishedAt = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
|
|
_capPublisher.Publish(TopicKeys.配置变更, new ConfigChangedMessage
|
|
{
|
|
ConfigType = "GameConfig",
|
|
OperationId = operationId,
|
|
PublishedAtUnixMs = publishedAt
|
|
});
|
|
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "[GameConfig] CAP配置变更事件发布失败 operationId={OperationId}", operationId);
|
|
}
|
|
|
|
return saveResult;
|
|
}
|
|
|
|
private static void NormalizeFishReferences(GameConfig gameConfig)
|
|
{
|
|
if (gameConfig == null)
|
|
return;
|
|
|
|
gameConfig.FishTypeConfigs ??= new List<FishTypeConfig>();
|
|
gameConfig.FishArrayConfigs ??= new List<FishArrayConfig>();
|
|
gameConfig.RoomFishConfigs ??= new List<RoomFishConfig>();
|
|
|
|
var validFishNumbers = gameConfig.FishTypeConfigs
|
|
.Where(f => f != null && !string.IsNullOrWhiteSpace(f.FishNumber))
|
|
.Select(f => f.FishNumber)
|
|
.ToHashSet(StringComparer.Ordinal);
|
|
|
|
gameConfig.FishArrayConfigs = gameConfig.FishArrayConfigs
|
|
.Where(a => a != null
|
|
&& (string.IsNullOrWhiteSpace(a.FishNumber) || validFishNumbers.Contains(a.FishNumber))
|
|
&& (string.IsNullOrWhiteSpace(a.BossFishNumber) || validFishNumbers.Contains(a.BossFishNumber)))
|
|
.ToList();
|
|
var validArrayNumbers = gameConfig.FishArrayConfigs
|
|
.Where(a => !string.IsNullOrWhiteSpace(a.FishArrayNumber))
|
|
.Select(a => a.FishArrayNumber)
|
|
.ToHashSet(StringComparer.Ordinal);
|
|
|
|
bool IsValidRoomFish(RoomFishDetailConfig item) => item != null && item.Type switch
|
|
{
|
|
1 => validFishNumbers.Contains(item.FishNumber),
|
|
2 => validArrayNumbers.Contains(item.FishNumber),
|
|
_ => false
|
|
};
|
|
|
|
foreach (var roomFishConfig in gameConfig.RoomFishConfigs.Where(c => c != null))
|
|
{
|
|
roomFishConfig.NormalFishList = (roomFishConfig.NormalFishList ?? new List<RoomFishDetailConfig>())
|
|
.Where(IsValidRoomFish).ToList();
|
|
roomFishConfig.RoomFishLevelList = (roomFishConfig.RoomFishLevelList ?? new List<RoomFishLevelConfig>())
|
|
.Where(IsValidRoomFish).ToList();
|
|
}
|
|
|
|
static void CleanFishNumbers(BossConfig.BaseBossConfig config, HashSet<string> validNumbers)
|
|
{
|
|
if (config == null) return;
|
|
config.FishNumber = (config.FishNumber ?? new List<string>())
|
|
.Where(validNumbers.Contains).Distinct().ToList();
|
|
}
|
|
|
|
var boss = gameConfig.BossConfigs;
|
|
if (boss != null)
|
|
{
|
|
boss.LuckWheel = (boss.LuckWheel ?? new List<BossConfig.LuckWheelConfig>())
|
|
.Where(c => c != null).ToList();
|
|
boss.LuckWheel.ForEach(c => CleanFishNumbers(c, validFishNumbers));
|
|
boss.LuckWheel = boss.LuckWheel.Where(c => c.FishNumber.Count > 0).ToList();
|
|
|
|
CleanFishNumbers(boss.LuckPoker, validFishNumbers);
|
|
|
|
boss.LuckFlyDisk = (boss.LuckFlyDisk ?? new List<BossConfig.LuckFlyDiskConfig>())
|
|
.Where(c => c != null).ToList();
|
|
boss.LuckFlyDisk.ForEach(c => CleanFishNumbers(c, validFishNumbers));
|
|
boss.LuckFlyDisk = boss.LuckFlyDisk.Where(c => c.FishNumber.Count > 0).ToList();
|
|
|
|
CleanFishNumbers(boss.FullScreen, validFishNumbers);
|
|
CleanFishNumbers(boss.Range, validFishNumbers);
|
|
CleanFishNumbers(boss.AmmunitionBox, validFishNumbers);
|
|
CleanFishNumbers(boss.InterstellarCruise, validFishNumbers);
|
|
CleanFishNumbers(boss.FlameStorm, validFishNumbers);
|
|
CleanFishNumbers(boss.Bomb, validFishNumbers);
|
|
CleanFishNumbers(boss.Scorpion, validFishNumbers);
|
|
|
|
boss.Probability = (boss.Probability ?? new List<BossConfig.BossProbabilityConfig>())
|
|
.Where(c => c != null).ToList();
|
|
boss.Probability.ForEach(c => CleanFishNumbers(c, validFishNumbers));
|
|
boss.Probability = boss.Probability.Where(c => c.FishNumber.Count > 0).ToList();
|
|
|
|
boss.LuckDragon = (boss.LuckDragon ?? new List<BossConfig.LuckDragonConfig>())
|
|
.Where(c => c != null).ToList();
|
|
boss.LuckDragon.ForEach(c => CleanFishNumbers(c, validFishNumbers));
|
|
boss.LuckDragon = boss.LuckDragon.Where(c => c.FishNumber.Count > 0).ToList();
|
|
}
|
|
|
|
if (gameConfig.RobotKillConfig != null)
|
|
{
|
|
gameConfig.RobotKillConfig.Scenes = (gameConfig.RobotKillConfig.Scenes ?? new List<RobotKillScene>())
|
|
.Where(s => s != null && validFishNumbers.Contains(s.FishNumber))
|
|
.ToList();
|
|
}
|
|
}
|
|
|
|
public async Task<(bool isok, string msg)> Delete()
|
|
{
|
|
_redis.RemoveGameConfig();
|
|
|
|
|
|
return await _mongo.DeleteOneAsync(c=>true);
|
|
|
|
}
|
|
|
|
|
|
|
|
public async Task<List<RedisGameRoom>> InitRoom(GameTypeEnum gameType = GameTypeEnum.None, int roomLevel = 0, GameConfig gameConfig = null)
|
|
{
|
|
|
|
List<RedisGameRoom> result = new List<RedisGameRoom>();
|
|
|
|
if (gameConfig == null)
|
|
{
|
|
gameConfig = await Get();
|
|
}
|
|
|
|
if (gameConfig == null || gameConfig.RoomConfigs == null || gameConfig.RoomConfigs.Count == 0)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
var roomConfig = gameConfig.RoomConfigs.AsEnumerable();
|
|
if (gameType != GameTypeEnum.None)
|
|
roomConfig = roomConfig.Where(c => c.GameType == gameType);
|
|
if (roomLevel > 0)
|
|
roomConfig = roomConfig.Where(c => c.RoomLevel == roomLevel);
|
|
|
|
var roomList = roomConfig.ToList();
|
|
if (roomList.Count == 0)
|
|
return result;
|
|
|
|
var initBotProfiles = RoomBotFactory.FixedBotSeatsEnabled
|
|
? _botProfileRepo.FilterBy(p => true).ToList()
|
|
: null;
|
|
|
|
foreach (var item in roomList.Where(c=>c.GameType!= GameTypeEnum.中国象棋))
|
|
{
|
|
var rateConfig = _emptyRoomRateRepo
|
|
.FilterBy(c => c.GameType == item.GameType && c.RoomLevel == item.RoomLevel && !c.IsDelete)
|
|
.FirstOrDefault();
|
|
var botsEnabled = gameConfig.BotConfig?.Enabled == true;
|
|
var emptyRate = botsEnabled ? Math.Clamp(rateConfig?.EmptyRoomRate ?? 0, 0, 100) : 100;
|
|
var totalRoomCount = item.RoomPartitionNum * item.RoomCount;
|
|
var roomsWithBots = emptyRate > 0
|
|
? (int)Math.Floor(totalRoomCount * (100 - emptyRate) / 100.0)
|
|
: totalRoomCount;
|
|
var botRoomIndexes = Enumerable.Range(0, totalRoomCount)
|
|
.OrderBy(_ => global::System.Random.Shared.Next())
|
|
.Take(roomsWithBots)
|
|
.ToHashSet();
|
|
|
|
for (var i = 1; i <= item.RoomPartitionNum; i++)
|
|
{
|
|
_redis.RemoveGameRoom($"{(int)item.GameType}{item.RoomLevel}{i}");
|
|
|
|
for (int c = 0; c < item.RoomCount; c++)
|
|
{
|
|
RedisGameRoom room = new RedisGameRoom()
|
|
{
|
|
RoomName = item.RoomName,
|
|
GameType = item.GameType,
|
|
RoomLevel = item.RoomLevel,
|
|
RoomPartition = i,
|
|
RoomNumber = c,
|
|
MaxPlayerCount = (item.GameType == GameTypeEnum.星际迷航 || item.GameType == GameTypeEnum.中国象棋) ? 2 : 4,
|
|
CurrentOnlinePlayerCount = 0,
|
|
|
|
};
|
|
var roomIndex = (i - 1) * item.RoomCount + c;
|
|
room.RobotCount = botsEnabled && botRoomIndexes.Contains(roomIndex)
|
|
? global::System.Random.Shared.Next(1, room.MaxPlayerCount)
|
|
: 0;
|
|
room.RoomId = $"{(int)room.GameType}{room.RoomLevel}{room.RoomPartition}{c.ToString("00")}";
|
|
|
|
if (room.RobotCount > 0 && RoomBotFactory.FixedBotSeatsEnabled)
|
|
{
|
|
var fixedBots = RoomBotFactory.CreateFixedSeatBots(room, item, gameConfig, initBotProfiles);
|
|
if (fixedBots.Count > 0)
|
|
{
|
|
room.Players.AddRange(fixedBots);
|
|
room.RobotCount = fixedBots.Count;
|
|
}
|
|
}
|
|
|
|
result.Add(room);
|
|
}
|
|
}
|
|
}
|
|
foreach (var item in result)
|
|
{
|
|
_redis.SetGameRoom(item);
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
public Task<string> InitDefaultConfig()
|
|
{
|
|
return Task.FromResult("初始化配置请使用GameConfigController的Init接口");
|
|
}
|
|
|
|
public async Task ResetDefaultRoomConfigs()
|
|
{
|
|
var config = await Get();
|
|
if (config == null) return;
|
|
|
|
var chessConfigs = config.RoomConfigs?.Where(c => c.GameType == GameTypeEnum.中国象棋).ToList() ?? new List<RoomConfig>();
|
|
|
|
config.RoomConfigs = new List<RoomConfig>();
|
|
|
|
config.RoomConfigs.Add(new RoomConfig() { RoomNumber = "20011", RoomName = "初级场", GameType = GameTypeEnum.风雷之渊, RoomLevel = 1, RoomPartitionNum = 4, RoomCount = 100, RoomGoldLimit = 100000, CannonMultipleList = new List<int> { 1000, 2000, 3000, 5000, 6000, 7000, 8000, 9000, 10000, 20000 } });
|
|
config.RoomConfigs.Add(new RoomConfig() { RoomNumber = "20012", RoomName = "中级场", GameType = GameTypeEnum.风雷之渊, RoomLevel = 2, RoomPartitionNum = 4, RoomCount = 100, RoomGoldLimit = 1000000, CannonMultipleList = new List<int> { 100, 200, 300, 500, 600, 700, 800, 900, 1000, 2000 } });
|
|
config.RoomConfigs.Add(new RoomConfig() { RoomNumber = "20013", RoomName = "高级场", GameType = GameTypeEnum.风雷之渊, RoomLevel = 3, RoomPartitionNum = 4, RoomCount = 100, RoomGoldLimit = 2000000, CannonMultipleList = new List<int> { 2000, 3000, 5000, 6000, 7000, 8000, 9000, 10000, 20000, 50000 } });
|
|
|
|
config.RoomConfigs.Add(new RoomConfig() { RoomNumber = "20021", RoomName = "初级场", GameType = GameTypeEnum.永夜尸城, RoomLevel = 1, RoomPartitionNum = 4, RoomCount = 100, RoomGoldLimit = 100000, CannonMultipleList = new List<int> { 1000, 2000, 3000, 5000, 6000, 7000, 8000, 9000, 10000, 20000 } });
|
|
config.RoomConfigs.Add(new RoomConfig() { RoomNumber = "20022", RoomName = "中级场", GameType = GameTypeEnum.永夜尸城, RoomLevel = 2, RoomPartitionNum = 4, RoomCount = 100, RoomGoldLimit = 1000000, CannonMultipleList = new List<int> { 100, 200, 300, 500, 600, 700, 800, 900, 1000, 2000 } });
|
|
config.RoomConfigs.Add(new RoomConfig() { RoomNumber = "20023", RoomName = "高级场", GameType = GameTypeEnum.永夜尸城, RoomLevel = 3, RoomPartitionNum = 4, RoomCount = 100, RoomGoldLimit = 2000000, CannonMultipleList = new List<int> { 2000, 3000, 5000, 6000, 7000, 8000, 9000, 10000, 20000, 50000 } });
|
|
|
|
config.RoomConfigs.Add(new RoomConfig() { RoomNumber = "20041", RoomName = "初级场", GameType = GameTypeEnum.星际迷航, RoomLevel = 1, RoomPartitionNum = 4, RoomCount = 100, RoomGoldLimit = 100000, CannonMultipleList = new List<int> { 1000, 2000, 3000, 5000, 6000, 7000, 8000, 9000, 10000, 20000 } });
|
|
config.RoomConfigs.Add(new RoomConfig() { RoomNumber = "20042", RoomName = "中级场", GameType = GameTypeEnum.星际迷航, RoomLevel = 2, RoomPartitionNum = 4, RoomCount = 100, RoomGoldLimit = 1000000, CannonMultipleList = new List<int> { 100, 200, 300, 500, 600, 700, 800, 900, 1000, 2000 } });
|
|
config.RoomConfigs.Add(new RoomConfig() { RoomNumber = "20043", RoomName = "高级场", GameType = GameTypeEnum.星际迷航, RoomLevel = 3, RoomPartitionNum = 4, RoomCount = 100, RoomGoldLimit = 2000000, CannonMultipleList = new List<int> { 2000, 3000, 5000, 6000, 7000, 8000, 9000, 10000, 20000, 50000 } });
|
|
|
|
config.RoomConfigs.Add(new RoomConfig() { RoomNumber = "20051", RoomName = "初级场", GameType = GameTypeEnum.黑神话悟空, RoomLevel = 1, RoomPartitionNum = 4, RoomCount = 100, RoomGoldLimit = 100000, CannonMultipleList = new List<int> { 1000, 2000, 3000, 5000, 6000, 7000, 8000, 9000, 10000, 20000 } });
|
|
config.RoomConfigs.Add(new RoomConfig() { RoomNumber = "20052", RoomName = "中级场", GameType = GameTypeEnum.黑神话悟空, RoomLevel = 2, RoomPartitionNum = 4, RoomCount = 100, RoomGoldLimit = 1000000, CannonMultipleList = new List<int> { 100, 200, 300, 500, 600, 700, 800, 900, 1000, 2000 } });
|
|
config.RoomConfigs.Add(new RoomConfig() { RoomNumber = "20053", RoomName = "高级场", GameType = GameTypeEnum.黑神话悟空, RoomLevel = 3, RoomPartitionNum = 4, RoomCount = 100, RoomGoldLimit = 2000000, CannonMultipleList = new List<int> { 2000, 3000, 5000, 6000, 7000, 8000, 9000, 10000, 20000, 50000 } });
|
|
|
|
if (chessConfigs.Any())
|
|
config.RoomConfigs.AddRange(chessConfigs);
|
|
|
|
await Update(config);
|
|
}
|
|
}
|
|
}
|