Files
BuYuHouDuan/FishGameSrc/FishGameService/GameSend/FishingSendService.cs
T

291 lines
12 KiB
C#
Raw Normal View History

2026-10-12 16:22:04 +08:00
using System.Text.Json;
using AutoMapper;
using Common.Utils;
using CommonService;
using FishGameService.GameSend;
using FishGameService.Hubs;
using FishGameService.Services;
using Microsoft.Extensions.Logging;
using RedisService.Param;
using StackExchange.Redis;
namespace Service.Fishing
{
public class FishingSendService : IFishingSendService
{
public readonly IHubSend<FishGameHub> _hubSend;
public readonly IMapper _mapper;
private readonly ISubscriber _subscriber;
private readonly ILogger<FishingSendService> _logger;
public FishingSendService(IHubSend<FishGameHub> hubSend, IMapper mapper, IConnectionMultiplexer redis, ILogger<FishingSendService> logger)
{
_hubSend = hubSend;
_mapper = mapper;
_subscriber = redis.GetSubscriber();
_logger = logger;
}
public void BindSuccess(string cid)
{
_hubSend.SendUserCId(cid, "BindSuccess", "绑定成功");
}
public void ErrorMessage(string cid, int code, string msg)
{
_hubSend.SendUserCId(cid, "Exception", new { code, message = msg });
}
public void KillNotice(string FishId, string userName, long gold = 0)
{
var msg = JsonSerializer.Serialize(new { Target = "All", Event = "KillNotice", Data = new { FishId, userName, gold } });
_subscriber.Publish("fishgame:global", msg);
}
public void KillNotice(string FishId, string userName, long gold, string fishName, long multiplier,
string gameTypeName, string roomName, long timestamp)
{
var text = $"恭喜玩家{userName}在{gameTypeName}{roomName}捕获 {fishName}*{multiplier}炮倍 {gold}大奖";
var data = new
{
Text = text,
UserName = userName,
GameTypeName = gameTypeName,
RoomName = roomName,
FishName = fishName,
Multiple = multiplier,
Gold = gold,
Time = timestamp,
FishId
};
var msg = JsonSerializer.Serialize(new { Target = "All", Event = "KillNotice", Data = data });
_subscriber.Publish("fishgame:global", msg);
}
public async Task SendRoomInfo(string cid, RedisGameRoom roomInfo, List<ActiveFish> activeFishes = null, bool sendInitialFish = true)
2026-10-12 16:22:04 +08:00
{
object payload;
List<object> initialFishPayload = null;
2026-10-12 16:22:04 +08:00
if (activeFishes != null && activeFishes.Count > 0)
{
initialFishPayload = BuildActiveFishPayload(activeFishes);
2026-10-12 16:22:04 +08:00
payload = new
{
roomInfo.RoomId,
roomInfo.RoomName,
roomInfo.GameType,
roomInfo.RoomLevel,
roomInfo.RoomPartition,
roomInfo.RoomNumber,
roomInfo.MaxPlayerCount,
roomInfo.CurrentOnlinePlayerCount,
roomInfo.RobotCount,
roomInfo.Players,
roomInfo.CreateUserId,
roomInfo.SystemFactor,
activeFishes = initialFishPayload
2026-10-12 16:22:04 +08:00
};
}
else
{
payload = roomInfo;
}
await _hubSend.SendUserCIdAsync(cid, "RoomInfo", payload);
if (sendInitialFish && initialFishPayload != null && initialFishPayload.Count > 0)
2026-10-12 16:22:04 +08:00
{
_ = SendInitialFishAfterSceneReady(cid, roomInfo.RoomId, initialFishPayload);
2026-10-12 16:22:04 +08:00
}
}
/// <summary>
/// 补发场上活鱼(挂起恢复 / 重连专用独立协议):
/// 发到独立事件 OnFishResync,客户端按"全量替换"处理(先清本地旧鱼,再按本列表重建)。
/// fish 列表口径与 RoomInfo.activeFishes / 首屏 init 完全一致,都带服务端原始的 createdAt。
/// </summary>
public async Task FishResyncNoticeAsync(string cid, string roomId, List<ActiveFish> activeFishes)
{
var fish = activeFishes == null || activeFishes.Count == 0
? new List<object>()
: BuildActiveFishPayload(activeFishes);
var now = DateTimeOffset.UtcNow;
await _hubSend.SendUserCIdAsync(cid, "OnFishResync", new
{
roomId,
timestamp = now.ToUnixTimeMilliseconds(),
serverTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"),
count = fish.Count,
fish
});
}
/// <summary>
/// 把场上活鱼转成下发 payload:单体鱼逐条、鱼阵按 FishArrayNumber 分组(鱼阵用首条 fishId 作主键)。
/// createdAt / expireAt 一律取服务端原始值,客户端据此按 (当前时间 - createdAt) / 路径总时长 推算位置。
/// </summary>
private static List<object> BuildActiveFishPayload(List<ActiveFish> activeFishes)
{
var now = DateTimeOffset.UtcNow;
return activeFishes
.Where(f => f != null && string.IsNullOrWhiteSpace(f.FishArrayNumber))
.Select(f => (object)new
{
fishId = f.FishId,
fishIds = new[] { f.FishId },
fishNumber = f.FishNumber,
routeId = f.ClientRouteId,
fishArrayNumber = string.Empty,
createdAt = new DateTimeOffset(f.CreatedAt).ToUnixTimeMilliseconds(),
createdTime = f.CreatedAt.ToString("yyyy-MM-dd HH:mm:ss.fff"),
expireAt = new DateTimeOffset(f.ExpireAt).ToUnixTimeMilliseconds(),
expireTime = f.ExpireAt.ToString("yyyy-MM-dd HH:mm:ss.fff"),
remainingSeconds = (int)Math.Max(0, (new DateTimeOffset(f.ExpireAt) - now).TotalSeconds)
})
.Concat(
activeFishes
.Where(f => f != null && !string.IsNullOrWhiteSpace(f.FishArrayNumber))
.GroupBy(f => f.FishArrayNumber)
.Select(group =>
{
var first = group.First();
return (object)new
{
fishId = first.FishId,
fishIds = group.Select(f => f.FishId).ToList(),
fishNumber = string.Empty,
routeId = first.ClientRouteId,
fishArrayNumber = first.FishArrayNumber,
createdAt = new DateTimeOffset(first.CreatedAt).ToUnixTimeMilliseconds(),
createdTime = first.CreatedAt.ToString("yyyy-MM-dd HH:mm:ss.fff"),
expireAt = new DateTimeOffset(group.Min(f => f.ExpireAt)).ToUnixTimeMilliseconds(),
expireTime = group.Min(f => f.ExpireAt).ToString("yyyy-MM-dd HH:mm:ss.fff"),
remainingSeconds = (int)Math.Max(0, (new DateTimeOffset(group.Min(f => f.ExpireAt)) - now).TotalSeconds)
};
}))
.ToList();
}
2026-10-12 16:22:04 +08:00
private async Task SendInitialFishAfterSceneReady(string cid, string roomId, List<object> initialFishPayload)
{
try
{
await Task.Delay(300);
var syncNow = DateTimeOffset.UtcNow;
await _hubSend.SendUserCIdAsync(cid, "OnFishSpawn", new
{
type = "init",
timestamp = syncNow.ToUnixTimeMilliseconds(),
serverTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"),
fish = initialFishPayload
});
}
catch (Exception ex)
{
_logger.LogWarning(ex,
"[Socket][FishSpawnData] 首屏鱼延迟补发失败 roomId={RoomId} targetCid={Cid} fishCount={FishCount}",
roomId, cid, initialFishPayload.Count);
}
}
public void RoomKillNotice(string roomId, string fishNumber, string userId, long gold, string fishId, long timespan, double beishu = 1,long skillsGold=0,int fishScore=1, object param = null, object drop = null, long gainExp = 0, long exp = 0, int level = 0, long expMax = 0)
2026-10-12 16:22:04 +08:00
{
var killtime=DateTime.Now.ToTimeStamp();
_hubSend.SendGroup(roomId, "RoomKillNotice", new { fishNumber, userId, gold, fishId, timespan, killtime, msg = $"时间:{killtime - timespan}秒", beishu, skillsGold, fishScore, param, drop, gainExp, exp, level, expMax });
2026-10-12 16:22:04 +08:00
}
public void RoomDisconnectNotice(string roomId, string userId)
{
_hubSend.SendGroup(roomId, "RoomDisconnectNotice", userId);
}
public void RoomJoinNotice(string roomId, RedisGamePlayer player)
{
_hubSend.SendGroup(roomId, "RoomJoinNotice", player);
}
public void ChangeGunMultipleNotice(string roomId, string userId, int multiple)
{
_hubSend.SendGroup(roomId, "ChangeGunMultipleNotice", new { userId, multiple });
}
public void RoomFireNotice(string roomId, string userId, List<string> bulletIds, long gold, int count, object extra = null, bool isBot = false)
{
_hubSend.SendGroup(roomId, "RoomFireNotice", new { userId, bulletIds, gold, count, extra, isBot });
}
public Task RoomFireNoticeAsync(string roomId, string callerCid, string userId, List<string> bulletIds, long gold, int count, object extra = null, bool isBot = false)
{
var payload = new { userId, bulletIds, gold, count, extra, isBot };
return Task.WhenAll(
_hubSend.SendUserCIdAsync(callerCid, "RoomFireNotice", payload),
_hubSend.GroupExceptAsync(callerCid, roomId, "RoomFireNotice", payload));
}
public void SyncPlayerGold(string cid, long gold)
{
_hubSend.SendUserCId(cid, "SyncPlayerGold", gold);
}
public void SendPlayerInfo(string cid, RedisGamePlayer player)
{
_hubSend.SendUserCId(cid, "SendPlayerInfoResult", player?.Gold);
}
public void RoomLeaveNotice(string roomId, string userId)
{
_hubSend.SendGroup(roomId, "RoomLeaveNotice", userId);
}
public void BotLeaveRoomNotice(string roomId, string userId)
{
_hubSend.SendGroup(roomId, "BotLeaveRoomNotice", new { userId });
}
public void ChangeControllerUser(string roomId, string userId)
{
_hubSend.SendGroup(roomId, "ChangeControllerUser", userId);
}
public void HostDisconnectNotice(string roomId)
{
_hubSend.SendGroup(roomId, "HostDisconnect", null);
}
public void SyncGameData(string roomId, object data)
{
_hubSend.SendGroup(roomId, "SyncGameData", data);
}
public void UsePropNotice(string roomId, string userId, string propNumber)
{
_hubSend.SendGroup(roomId, "UsePropNotice", new { userId, propNumber });
}
public void TorpedoResultNotice(string roomId, string userId, string propNumber, long gold, string color)
{
_hubSend.SendGroup(roomId, "TorpedoResultNotice", new { userId, propNumber, gold, color });
}
public void PlayerAfkNotice(string roomId, string userId)
{
_hubSend.SendGroup(roomId, "PlayerAfkNotice", new { userId });
}
public void PlayerCancelAfkNotice(string roomId, string userId)
{
_hubSend.SendGroup(roomId, "PlayerCancelAfkNotice", new { userId });
}
}
}