300 lines
12 KiB
C#
300 lines
12 KiB
C#
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<BotAddScoreAction> 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;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Schedule a new action queue for the robot.
|
|
/// </summary>
|
|
/// <param name="botScore">Current score added by bot.</param>
|
|
/// <param name="totalScore">Current total score.</param>
|
|
public void Schedule(int botScore, int totalScore)
|
|
{
|
|
var tableConfig = GContext.container.Resolve<Tables>().TbEventPartnerConfig;
|
|
ActionQ = new Queue<BotAddScoreAction>();
|
|
var currentProgress = _arc.Ctx.GetStageFromTotalScore(totalScore);
|
|
var robotData = GContext.container.Resolve<Tables>().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($"<color=#c191ff>[EventPartner]New bot target {newBotTargetScore} is smaller than old target {TargetScore}</color>");
|
|
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($"<color=#c191ff>[EventPartnerStatue]Split {gap} into {scheduleAmount}.</color>");
|
|
UnityEngine.Debug.Log($"<color=#c191ff>[EventPartnerStatue]WakeTime:{WakeStartTime}, StartTime: {startTime}, Duration: {scheduleDuration}s, Add {gap} points in {scheduleAmount} times.</color>");
|
|
UnityEngine.Debug.Log($"<color=#c191ff>[EventPartnerStatue]Activation Delay: {startTime - WakeStartTime}, BotAddScoreStrengthGrade: {Grade}</color>");
|
|
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($"<color=#c191ff>[EventPartnerStatue] Add {a.Score} @ {a.DueTime}.</color>");
|
|
}
|
|
|
|
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<Tables>().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<string, Robot> RobotList = new Dictionary<string, Robot>();
|
|
public Queue<RobotInvitation> RobotInvitationBuffer = new Queue<RobotInvitation>();
|
|
private bool _isLoopActive = false;
|
|
private TimeSpan _loopInterval = TimeSpan.FromSeconds(10);
|
|
public const char RobotIdentifier = 'R';
|
|
private static readonly IUserService UserService = GContext.container.Resolve<IUserService>();
|
|
private static readonly TbRobot RobotTable = GContext.container.Resolve<Tables>().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($"<color=cyan>[EventPartnerStatue]Adding bot {invitation.Id}, with due time {invitation.DueTime}</color>");
|
|
var resp = await _arc.Requests.Accept(invitation.Id);
|
|
if (resp == null || resp.State != EEventBuildState.Success)
|
|
{
|
|
OnBotInvitationFail(invitation);
|
|
UnityEngine.Debug.Log($"<color=cyan>[EventPartnerStatue] Fail: {resp.State}.</color>");
|
|
continue;
|
|
}
|
|
OnBotInvitationSuccess(invitation.Id);
|
|
UnityEngine.Debug.Log($"<color=cyan>[EventPartnerStatue] Success: {resp.State}.</color>");
|
|
}
|
|
}
|
|
|
|
public void TryAddScore()
|
|
{
|
|
var arc = GContext.container.Resolve<EventPartnerStatueArc>();
|
|
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<Tables>().TbEventPartnerRobot;
|
|
var tableConfig = GContext.container.Resolve<Tables>().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<BotAddScoreAction> ActionQ { get; set; }
|
|
}
|
|
public class EventBotAdd { public int SlotId { get; set; } }
|
|
} |