using cfg; using asap.core; using game; using System.Globalization; using GameCore; using System; using System.Collections.Generic; using System.Linq; using EventPartnerGatherRequests; using Castle.Core.Internal; namespace EventPartner { public class Robot { public string Id; public string Avatar; public string DisplayName; public DateTime WakeStartTime; public float WakingSeconds; public int Grade; public int TargetScore; public Queue ActionQ; private IEventPartnerArchitecture _arc; public Robot(string id, string avatar, string displayName, DateTime wakeStartTime, float wakingSeconds, int grade, IEventPartnerArchitecture arc) { Id = id; Avatar = avatar; DisplayName = displayName; WakeStartTime = wakeStartTime; WakingSeconds = wakingSeconds; Grade = grade; _arc = arc; Schedule(0, 0); } public Robot(RobotPlayerPreferenceData data, IEventPartnerArchitecture arc) { Id = data.Id; WakeStartTime = data.WakeStartTime; WakingSeconds = data.WakingSeconds; Grade = data.Grade; TargetScore = data.TargetScore; ActionQ = data.ActionQ; _arc = arc; } /// /// Schedule a new action queue for the robot. /// /// Current score added by bot. /// Current total score. public void Schedule(int botScore, int totalScore) { var tableConfig = GContext.container.Resolve().TbEventPartnerConfig; ActionQ = new Queue(); var currentProgress = _arc.Ctx.GetStageFromTotalScore(totalScore); var robotData = GContext.container.Resolve().TbEventPartnerRobot.DataList[Grade]; var percentage = UnityEngine.Random.Range(robotData.PointsRange[0], robotData.PointsRange[1]) / 100; int newBotTargetScore = (int)(percentage * _arc.Ctx.GetTargetScoreByStage(currentProgress)); if (newBotTargetScore < TargetScore) { UnityEngine.Debug.Log($"[EventPartner]New bot target {newBotTargetScore} is smaller than old target {TargetScore}"); return; } var startTime = WakeStartTime; startTime += TimeSpan.FromDays(ZZTimeHelper.UtcNow().Day - startTime.Day); startTime += TimeSpan.FromSeconds(UnityEngine.Random.Range(0, WakingSeconds)); var scheduleDuration = UnityEngine.Random.Range(tableConfig.RobotSingleAddPointsTimeWindow[0], tableConfig.RobotSingleAddPointsTimeWindow[1]); var scheduleAmount = UnityEngine.Random.Range(tableConfig.RobotSingleAddPointsOperations[0], tableConfig.RobotSingleAddPointsOperations[1]); var timeList = Enumerable.Range(1, scheduleDuration) .OrderBy(_ => UnityEngine.Random.value) .Take(scheduleAmount) .OrderBy(t => t) .ToList(); var gap = newBotTargetScore - botScore; if (!FtUtils.RandomSplit(gap, scheduleAmount, out var scoreList)) UnityEngine.Debug.Log($"[EventPartnerStatue]Split {gap} into {scheduleAmount}."); UnityEngine.Debug.Log($"[EventPartnerStatue]WakeTime:{WakeStartTime}, StartTime: {startTime}, Duration: {scheduleDuration}s, Add {gap} points in {scheduleAmount} times."); UnityEngine.Debug.Log($"[EventPartnerStatue]Activation Delay: {startTime - WakeStartTime}, BotAddScoreStrengthGrade: {Grade}"); int minWheelNumber = _arc.Ctx.GetMinSpinPoint(); for (int i = 0; i < scoreList.Count; i++) { FtUtils.ScaleByBase(scoreList[i], minWheelNumber, out var score); ActionQ.Enqueue(new BotAddScoreAction { Score = score, DueTime = startTime + TimeSpan.FromSeconds(timeList[i]) }); } _arc.SavePlayerPreference(); foreach (var a in ActionQ) UnityEngine.Debug.Log($"[EventPartnerStatue] Add {a.Score} @ {a.DueTime}."); } public RobotPlayerPreferenceData ToPpData() { return new RobotPlayerPreferenceData { Id = Id, WakeStartTime = WakeStartTime, WakingSeconds = WakingSeconds, Grade = Grade, TargetScore = TargetScore, ActionQ = ActionQ }; } } public class BotAddScoreAction { public DateTime DueTime { get; set; } public int Score { get; set; } } public class RobotInvitation { public string Id { get; set; } public DateTime DueTime { get; set; } private (int from, int to) GetInvitationWindow() { var configTable = GContext.container.Resolve().TbEventPartnerConfig; return (configTable.RobotAgreeTime[0], configTable.RobotAgreeTime[1]); } public RobotInvitation(string id) { Id = id; var (from, to) = GetInvitationWindow(); DueTime = ZZTimeHelper.UtcNow() + TimeSpan.FromSeconds(UnityEngine.Random.Range(from, to)); } } public class RobotDataManager { public Dictionary RobotList = new Dictionary(); public Queue RobotInvitationBuffer = new Queue(); private bool _isLoopActive = false; private TimeSpan _loopInterval = TimeSpan.FromSeconds(10); public const char RobotIdentifier = 'R'; private static readonly IUserService UserService = GContext.container.Resolve(); private static readonly TbRobot RobotTable = GContext.container.Resolve().TbRobot; private readonly IEventPartnerArchitecture _arc; public RobotDataManager(IEventPartnerArchitecture arc) { _arc = arc; } public static string Idx2Id(int idx) { return idx.ToString("X5") + RobotIdentifier; } public static int Id2Idx(string id) { return int.Parse(id.Trim(RobotIdentifier), NumberStyles.HexNumber); } public static void GetBotDisplayInfo(string id, out string avatar, out string displayName) { int idx = Id2Idx(id); var res = RobotTable.DataMap.TryGetValue(idx, out var r); if (!res) { avatar = ""; displayName = UserService.GetDefaultName(id); return; } avatar = r.Avatar; displayName = LocalizationMgr.GetText(r.Name_l10n_key); } public static bool IsRobot(string id) { return id.EndsWith(RobotIdentifier); } public void PushToBuffer(string robotId) { RobotInvitationBuffer.Enqueue(new RobotInvitation(robotId)); _arc.SavePlayerPreference(); } public async System.Threading.Tasks.Task TryBotInvitation() { while (!_arc.IsFull() && RobotInvitationBuffer.Count > 0 && RobotInvitationBuffer.Peek().DueTime < ZZTimeHelper.UtcNow()) { var invitation = RobotInvitationBuffer.Dequeue(); _arc.SavePlayerPreference(); UnityEngine.Debug.Log($"[EventPartnerStatue]Adding bot {invitation.Id}, with due time {invitation.DueTime}"); var resp = await _arc.Requests.Accept(invitation.Id); if (resp == null || resp.State != EEventBuildState.Success) { OnBotInvitationFail(invitation); UnityEngine.Debug.Log($"[EventPartnerStatue] Fail: {resp.State}."); continue; } OnBotInvitationSuccess(invitation.Id); UnityEngine.Debug.Log($"[EventPartnerStatue] Success: {resp.State}."); } } public void TryAddScore() { var arc = GContext.container.Resolve(); foreach (var robot in RobotList.Values) { if (!robot.ActionQ.TryPeek(out var addScoreAction) || ZZTimeHelper.UtcNow() < addScoreAction.DueTime) continue; var c = arc.Model.ComponentList.FirstOrDefault(c => c.PartnerId == robot.Id); if (c == null) { UnityEngine.Debug.LogWarning($"[EventPartnerStatue]Robot {robot.Id} not found in component list. SUS."); continue; } if (c.ScoreTotal >= arc.TableContext.GetMaxScore()) { robot.ActionQ.Clear(); continue; } while (!robot.ActionQ.IsNullOrEmpty() && ZZTimeHelper.UtcNow() >= robot.ActionQ.Peek().DueTime) { var action = robot.ActionQ.Dequeue(); c.AddPartnerScore(action.Score); UnityEngine.Debug.Log($"[EventPartnerStatue] Add robot score to {c.PartnerId} with {action.Score} at {action.DueTime}"); arc.SavePlayfab();// To save score; arc.SavePlayerPreference(); // To update action queue. } } } private void OnBotInvitationSuccess(string botId) { _arc.InvitationData.OnAccept(botId); CreateBotDataToRobotList(botId); _arc.AddPartner(botId); _arc.EventAggregator.Publish(new EventBotAdd()); } public void CreateBotDataToRobotList(string botId) { var tableRobot = GContext.container.Resolve().TbEventPartnerRobot; var tableConfig = GContext.container.Resolve().TbEventPartnerConfig; var grade = FtUtils.GetRandomIdxFromWeightList(tableRobot.DataList.Select(r => r.Weight)); var wakeStartTime = ZZTimeHelper.UtcNow(); int wakingSeconds = UnityEngine.Random.Range(tableConfig.RobotDailyActiveTimeWindow[0], tableConfig.RobotDailyActiveTimeWindow[1]); GetBotDisplayInfo(botId, out string avatar, out string displayName); RobotList.Add(botId, new Robot(botId, avatar, displayName, wakeStartTime, wakingSeconds, grade, _arc)); } private void OnBotInvitationFail(RobotInvitation invitation) { _arc.InvitationData.OnRefuse(invitation.Id); } public async void StartRobotLoop() { try { if (_isLoopActive) return; _isLoopActive = true; while (_isLoopActive) { await TryBotInvitation(); TryAddScore(); await System.Threading.Tasks.Task.Delay(_loopInterval); } } catch (Exception e) { _isLoopActive = false; UnityEngine.Debug.LogError(e); // await System.Threading.Tasks.Task.Delay(_loopInterval); // StartRobotLoop(); } } public void CutRobotLoop() { _isLoopActive = false; } } public class RobotPlayerPreferenceData { public string Id { get; set; } public DateTime WakeStartTime { get; set; } public float WakingSeconds { get; set; } public int Grade { get; set; } public int TargetScore { get; set; } public Queue ActionQ { get; set; } } public class EventBotAdd { public int SlotId { get; set; } } }