using System.Collections.Generic; namespace ET.Server { [MessageSessionHandler(SceneType.Gate)] [FriendOf(typeof(GachaComponent))] public class C2G_GachaDrawHandler : RpcMessageHandler { protected override async ETTask OnRun(Session session, C2G_GachaDraw request, R2C_GachaDraw response) { SessionPlayerComponent sessionPlayer = session.GetComponent(); Player player = sessionPlayer?.Player; if (player == null) { response.Error = ErrorCode.ERR_RpcFail; response.Message = "Player not found"; return; } GachaComponent gacha = player.GetComponent() ?? player.AddComponent(); if (!gacha.PoolStats.TryGetValue(request.poolId, out GachaPoolState state)) { state = new GachaPoolState(); gacha.PoolStats[request.poolId] = state; } long now = TimeInfo.Instance.ServerNow(); if (now - state.LastDrawMs < 100) { response.Error = ErrorCode.ERR_GACHA_RATE_LIMIT; response.Message = "Rate limited"; Log.Error($"[L3][Gacha] player={player.Id} poolId={request.poolId} rate-limit"); return; } BagComponent bag = player.GetComponent() ?? player.AddComponent(); List rewards = gacha.Draw(request.poolId, (GachaDrawType)request.drawType, bag); response.rewards.AddRange(rewards); foreach (RewardEntry reward in rewards) { response.isNewHero.Add(reward.ItemId >= 10000); } Gacha_GachaInfo info = Gacha_GachaInfo.Create(); foreach (var kv in gacha.PoolStats) { GachaPoolStats stat = GachaPoolStats.Create(); stat.poolId = kv.Key; stat.totalCount = kv.Value.TotalCount; stat.guaranteeRemain = kv.Value.GuaranteeRemain; info.stats.Add(stat); } session.Send(info); LogExtensions.Audit("Gacha", "DrawHandler", $"{{\"playerId\":{player.Id},\"poolId\":{request.poolId},\"count\":{rewards.Count}}}"); await ETTask.CompletedTask; } } }